prompt Package Body : jr_folder create or replace package body jr_folder is ------------------------------------------------ -- * Package : Private data/methods * ------------------------------------------------ ------------------------------------------------ -- Procedure : put_line ------------------------------------------------ procedure put_line(msg varchar2) is begin jr_reg_io.put_line(msg); end put_line; --------------------------------------------------------------------------- -- Procedure which creates a new folder and registers it with the specified folder. -- Returns folder_irid and folder_ivid of folder (new or exisiting) -- RJM 26/8/98 --------------------------------------------------------------------------- procedure register_folder (folder_name in varchar2, folder_irid out number, folder_ivid out number, folder_ref in number, folder_status out varchar2) is case_sens_flg varchar2(1); begin case_sens_flg := jr_policy.get_policy('CASE_SENSITIVE_FILENAMES'); if case_sens_flg is null then case_sens_flg := 'N'; end if; --see if the file exists in this folder already if folder_ref is not null then if case_sens_flg = 'Y' then select f.irid, f.ivid into folder_irid, folder_ivid from sdd_folders f, sdd_folder_members m where f.irid = m.member_object and m.folder_reference = folder_ref and f.name = folder_name; else select f.irid, f.ivid into folder_irid, folder_ivid from sdd_folders f, sdd_folder_members m where f.irid = m.member_object and m.folder_reference = folder_ref and nls_upper(f.name) = nls_upper(folder_name); end if; else --root folder if folder_ref == NULL if case_sens_flg = 'Y' then select irid, ivid into folder_irid, folder_ivid from sdd_root_container_elements where name = folder_name; -- and root_flag = 'Y'; else select irid, ivid into folder_irid, folder_ivid from sdd_root_container_elements where nls_upper(name) = nls_upper(folder_name); -- and root_flag = 'Y'; end if; end if; --if the object exists, find out its current state and return as a char IF jr_version.is_checked_in(folder_irid, folder_ivid) THEN folder_status := 'I'; ELSE folder_status := 'O'; END IF; dbms_output.put_line(folder_name||' IRID:IVID:STATUS = '||folder_irid||':'||folder_ivid||':'||folder_status); exception when no_data_found then declare ctxt_ivid number; new_ivid number; begin ctxt_ivid := 0; new_ivid := 0; --create new file, versioning context if necessary... if folder_ref is not null then select ivid into ctxt_ivid from sdd_folders where irid = folder_ref; if jr_version.is_checked_in(folder_ref, ctxt_ivid) then new_ivid := jr_version.check_out(folder_ref, ctxt_ivid, TRUE, ''); end if; end if; jr_folder.new_folder(folder_name, folder_ref, folder_irid, folder_ivid); folder_status := 'N'; dbms_output.put_line(folder_name||' IRID:IVID:STATUS = '||folder_irid||':'||folder_ivid||folder_status); if new_ivid != 0 then new_ivid := jr_version.check_in(folder_ref, new_ivid, 'Created element '||folder_name, null); end if; exception when others then raise; end; when others then raise; end; --------------------------------------------------------------------------- -- -- Procedure which returns the details required to sync a folder path -- --------------------------------------------------------------------------- procedure getSyncDetails (rootFolderName in varchar2, strPath in varchar2, rootFolderIRID out number, ctxtFolderIRID out number, ctxtFolderIVID out number, ctxtFolderStatus out varchar2) is case_sens_flg varchar2(1); begin getSyncDetails2(rootFolderName,strPath,rootFolderIRID,ctxtFolderIRID, ctxtFolderIVID,ctxtFolderStatus,case_sens_flg); end; --------------------------------------------------------------------------- -- -- Procedure which returns the details required to sync a folder path -- NOTE: Also returns case sens flag (which it makes use of) -- --------------------------------------------------------------------------- procedure getSyncDetails2 (rootFolderName in varchar2, strPath in varchar2, rootFolderIRID out number, ctxtFolderIRID out number, ctxtFolderIVID out number, ctxtFolderStatus out varchar2, case_sens_flg out varchar2) is changed_naming_mode boolean; begin changed_naming_mode := false; case_sens_flg := jr_policy.get_policy('CASE_SENSITIVE_FILENAMES'); if case_sens_flg is null then case_sens_flg := 'N'; end if; if case_sens_flg = 'N' then select irid into rootFolderIRID from sdd_root_container_elements where nls_upper(name) = nls_upper(rootFolderName); -- and root_flag = 'Y'; else select irid into rootFolderIRID from sdd_root_container_elements where name = rootFolderName; -- and root_flag = 'Y'; end if; -- set case sens for naming service if case_sens_flg = 'N' then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); changed_naming_mode := true; end if; else if not jr_name.case_sensitive() then jr_name.enable_case_sensitivity(); changed_naming_mode := true; end if; end if; jr_name.get_RID_VID(strPath, ctxtFolderIRID, ctxtFolderIVID); -- reset case sens for naming service if changed_naming_mode then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); else jr_name.enable_case_sensitivity(); end if; changed_naming_mode := false; end if; select state into ctxtFolderStatus from i$sdd_object_versions where irid = ctxtFolderIRID and ivid = ctxtFolderIVID; exception when others then -- reset case sens for naming service if changed_naming_mode then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); else jr_name.enable_case_sensitivity(); end if; end if; raise; end; --------------------------------------------------------------------------- -- Procedure which returns the context folder id for a given path and root -- folder ID -- RJM 26/8/98 --------------------------------------------------------------------------- procedure getContextFolderID (rootFolderRef in number, strPath in varchar2, contextFolderIRID out number, contextFolderIVID out number, folder_status out varchar2) is case_sens_flg varchar2(1); begin getContextFolderID2 (rootFolderRef,strPath,contextFolderIRID, contextFolderIVID,folder_status,case_sens_flg); if contextFolderIRID is null then raise no_data_found; end if; end; --------------------------------------------------------------------------- -- Procedure which returns the context folder id for a given path and root -- folder ID -- NOTE: Also returns case sens flag (which it makes use of) -- RJM 07/01/2000 --------------------------------------------------------------------------- procedure getContextFolderID2 (rootFolderRef in number, strPath in varchar2, contextFolderIRID out number, contextFolderIVID out number, folder_status out varchar2, case_sens_flg out varchar2) is rootFolderName varchar2 (256); changed_naming_mode boolean; begin changed_naming_mode := false; case_sens_flg := jr_policy.get_policy('CASE_SENSITIVE_FILENAMES'); if case_sens_flg is null then case_sens_flg := 'N'; end if; rootFolderName := ''; if rootFolderRef is not null then select name into rootFolderName from sdd_folders where irid = rootFolderRef; end if; rootFolderName := rootFolderName||strPath; -- set case sens for naming service if case_sens_flg = 'N' then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); changed_naming_mode := true; end if; else if not jr_name.case_sensitive() then jr_name.enable_case_sensitivity(); changed_naming_mode := true; end if; end if; jr_name.get_RID_VID(rootFolderName, contextFolderIRID, contextFolderIVID); -- reset case sens for naming service if changed_naming_mode then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); else jr_name.enable_case_sensitivity(); end if; changed_naming_mode := false; end if; select state into folder_status from i$sdd_object_versions where irid = contextFolderIRID and ivid = contextFolderIVID; exception when no_data_found then -- reset case sens for naming service if changed_naming_mode then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); else jr_name.enable_case_sensitivity(); end if; changed_naming_mode := false; end if; contextFolderIRID := null; contextFolderIVID := null; when others then -- reset case sens for naming service if changed_naming_mode then if jr_name.case_sensitive() then jr_name.disable_case_sensitivity(); else jr_name.enable_case_sensitivity(); end if; changed_naming_mode := false; end if; raise; end; --------------------------------------------------------------------------- -- jr_folder.new_folder() -- create a new folder (within the context of a parent folder, if specified) -- through the CDAPI -- Thin wrapper for compatibility with previous code, returns irid. --------------------------------------------------------------------------- function new_folder(folder_name varchar2, context_folder number default null) return number is folder_irid number; folder_ivid number; BEGIN jr_folder.new_folder(folder_name, context_folder, folder_irid, folder_ivid); return folder_irid; end; --------------------------------------------------------------------------- -- jr_folder.new_folder() -- create a new folder (within the context of a parent folder, if specified) -- through the CDAPI -- Folder is created within the context of another (specified) folder. Setting -- the context folder to null creates a root folder. -- -- IMPORTANT: NO exception handling! Caller must catch and deal with -- exceptions --------------------------------------------------------------------------- procedure new_folder(folder_name in varchar2, context_folder in number default null, folder_irid out number, folder_ivid out number) is fol ciofolder.data; repos_ctxt_folder number; procedure o (text varchar2) is begin dbms_output.put_line(text); end; BEGIN --cache the current repository context folder repos_ctxt_folder := jr_context.working_folder; -- set the context folder cdapi.set_context_appsys(null,null,context_folder); -- disable uniqueness checking for the creation of this folder cioapp_con_interface.disable_unique_check := true; -- Get the insert values fol.v.NAME := folder_name; fol.i.NAME := true; -- create the new folder ciofolder.ins(null,fol); --output the current irid and ivid o('Folder IRID = '||fol.v.IRID); o('Folder IVID = '||fol.v.IVID); folder_irid := fol.v.IRID; folder_ivid := fol.v.IVID; -- re-enable uniqueness checking cioapp_con_interface.disable_unique_check := false; -- reset the repos ctxt folder cdapi.set_context_appsys(null,null,repos_ctxt_folder); EXCEPTION when others then --ensure uniqueness checking re-enabled cioapp_con_interface.disable_unique_check := false; RAISE; END; --------------------------------------------------------------------------- -- delete_folder -- delete a folder through the CDAPI -- -- IMPORTANT: NO exception handling! Caller must catch and deal with -- exceptions --------------------------------------------------------------------------- procedure delete_folder(folder_irid in number) is BEGIN -- delete the folder ciofolder.del(folder_irid); END; --------------------------------------------------------------------------- -- is_container -- -- Tests to see whether an element instance is a container type --------------------------------------------------------------------------- function is_container (object_irid number) return boolean is dummy number; begin jr_acc_rights.disable_view_checking; SELECT null INTO dummy FROM sdd_object_versions ov , rm_element_types et WHERE ov.irid = is_container.object_irid AND et.id = ov.logical_type_id AND et.supertypes = (SELECT cont.id FROM rm_element_types cont WHERE cont.name = 'CONTAINER_ELEMENT' ) ; jr_acc_rights.enable_view_checking; -- If the query returned a row then the object is a container return true; exception when no_data_found then jr_acc_rights.enable_view_checking; -- Query returned to rows, object is not a container return false; end is_container; --------------------------------------------------------------------------- -- Bind -- -- Bind the object into the current working folder (container) -- If there is no current working folder and the object is itself a folder -- (or any container) then the folder will be a root folder. -- --------------------------------------------------------------------------- procedure bind ( object_irid number -- the object to be bound , name_in_context name_atom default null -- name in context ) is fol_ivid number; wa_name varchar2(256); view_checking varchar2(1):=jr_acc_rights.view_checking; begin put_line('jr_folder.bind...start...'); -- Fix bug 876824, allow disabling of creation of folder members -- Note, this also bypasses access rights checking if (not jr_context.is_enabled(jr_context.FOLDER_MEMBERS)) then return ; end if; if jr_context.working_folder is not null then put_line('jr_folder.bind...jr_acc_rights.has_access ?...'); -- Check access rights if not jr_acc_rights.has_access(jr_context.working_folder, USER, 'INS') then put_line('jr_folder.bind...jr_acc_rights.has_access...No access rights...'); -- No access rights, get ivid of container so we can use naming service to -- display an error message select fol.ivid into fol_ivid from sdd_folders fol where fol.irid = jr_context.working_folder; --No insert privileges on folder %0!s rmmes.post('CDR', 2620, jr_name.get_path(fol_ivid,'NAME')); raise jr_acc_rights.access_rights_error; else put_line('jr_folder.bind...jr_acc_rights.has_access...access ok...'); -- Access rights ok, create the folder member -- Notes -- 1) the cdapi audit triggers will populate the types column -- 2) insert into base table to avoid access rights checks (new objects are -- allowed in checked-in folders -- -- There is a trigger on folder members which checks that member_object -- references a valid row in object versions. The access rights checking -- in the view definition queries folder members, which is mutating, and -- an error occurs. Can disable view checking here because we know what -- we're doing ! jr_acc_rights.disable_view_checking; insert into i$sdd_folder_members ( folder_reference , member_object , name_in_context , ownership_flag , visibility) values ( jr_context.working_folder , object_irid , name_in_context , 'Y' , 'PUBLIC'); jr_acc_rights.enable_view_checking; end if; else -- No context container is set if is_container(object_irid) then -- This is ok if the object being created is a (root) container itself -- Must have insert access right on the current workarea though. if jr_context.workarea is null then -- Workarea context must be set rmmes.post('CDR',100); raise no_workarea_context; end if; -- Check access rights if not jr_acc_rights.has_access(jr_context.workarea, USER, 'INS') then -- No access rights, get name of workarea to display in error message select wa.name into wa_name from sdd_workareas wa where wa.irid = jr_context.workarea; --Insufficient access rights to insert in workarea %0!s rmmes.post('CDR', 2625, wa_name); raise jr_acc_rights.access_rights_error; end if; else -- Folder context has not been set. rmmes.post('CDR',114); raise no_folder_context; end if; end if; exception when others then --Ensure we re-enable view checking, if it was previously enabled if view_checking='Y' then jr_acc_rights.enable_view_checking; end if; raise; end bind; --------------------------------------------------------------------------- ------ OLD STUFF: --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- remove this object from a context --------------------------------------------------------------------------- procedure unbind( object object_irid -- the object to be unbound ) is -- {{ the_context_folder folder_handle; begin delete from sdd_folder_members where member_object = object; end unbind; -- }} --------------------------------------------------------------------------- -- unbind, then bind --------------------------------------------------------------------------- procedure rebind( object object_irid -- the object to be bound ,context_folder folder_handle default null -- context folder ,name_in_context name_atom default null -- name in context ) is -- {{ begin begin unbind(object); exception when no_data_found then null; end; bind(object, context_folder); end rebind; -- }} --------------------------------------------------------------------------- -- REATTACH_OBJECT() -- This method is used to re-attach objects that have become orphaned -- to an owning container. An orphaned object is one with no owning -- container. Orphaned objects can be seen via the SDD_LOST_AND_FOUND view. -- Workarea context must be set when performing this operation. --------------------------------------------------------------------------- procedure reattach_object ( object_ivid in number , new_container in number , name_in_context in name_atom default null ) is p_object_ivid number := reattach_object.object_ivid; dummy number; l_object_irid number; context_folder number:=jr_context.working_folder; no_checkin_upd boolean:=jr_context.is_enabled(JR_CONTEXT.NO_CHECKIN_UPDATE); clash_irid number; clash_type number; el_type_name rm_element_type_extensions.nls_name%TYPE; begin --Get IRID for object select ov.irid into l_object_irid from I$SDD_OBJECT_VERSIONS ov where ov.ivid=p_object_ivid; --Ensure workarea context is set if jr_context.workarea is null then --No workare context set rmmes.post('CDR',100); RAISE no_workarea_context; end if; --Ensure object is orphan! if is_orphan(l_object_irid)='N' then select nls.nls_name into el_type_name from rm_element_type_extensions nls , I$SDD_OBJECT_VERSIONS ov where nls.for_type=ov.logical_type_id and ov.ivid=p_object_ivid; --%0!s %1!s is not orphaned rmmes.post('CDR',1055,el_type_name,jr_name.get_CRN(p_object_ivid,'NAME')); raise FOLDER_ERROR; end if; --There may be owning folder members for this element in the wastebasket, --if so, we set the ownership flag to N so that a restore does not result --in two owning folders --Allow update of checked in folder members jr_context.disable(JR_CONTEXT.NO_CHECKIN_UPDATE); update I$SDD_FOLDER_MEMBERS fm set fm.ownership_flag='N' where fm.member_object=l_object_irid and fm.ownership_flag='Y'; --Re-enable no update of checked in elements if no_checkin_upd then jr_context.enable(JR_CONTEXT.NO_CHECKIN_UPDATE); end if; --Set folder context as new owning container jr_context.set_working_folder(NULL,new_container); --Bind the object to new owning container --(will throw errors if container checked in, or user has insufficient -- access rights). bind(l_object_irid,name_in_context); --Add object into current workarea context, if its not already there --(and it most likely wont be there). -- CW 18-JUL-02 -- Fix bug 2449977 REATTACHING OBJECT FROM LOST+FOUND FAILS WITH ERRORS -- CDR-1054 AND ORA-1403 -- The name uniqueness check below was failing because the lost and found -- entry is already in i$sdd_wa_context but with the wastebasket column set -- to 'X' so the version resolved views cannot see the newly re-attached -- folder member. Reset the wastebasket column here instead. -- If the update statement updates no rows then insert a new row, as before. update i$sdd_wa_context ctxt set ctxt.wastebasket = jr_context.wastebasket where ctxt.workarea_irid = jr_context.workarea and ctxt.object_ivid = p_object_ivid ; if sql%rowcount = 0 then --If no version of object visible in current workarea, add it to context insert into I$SDD_WA_CONTEXT ( workarea_irid , object_ivid ) values ( jr_context.workarea , p_object_ivid ); end if; --Check name uniqueness for reattached element --(this must be done after we've performed the reattachment) if not jr_name.is_el_name_unique( new_container , l_object_irid , clash_irid , clash_type ) then select nls.nls_name into el_type_name from rm_element_type_extensions nls where nls.for_type=clash_type; --Cannot reattach %0!s. Name uniqueness conflict with %1!s %2!s rmmes.post('CDR',1056,jr_name.get_crn(p_object_ivid,'NAME') ,el_type_name ,jr_name.get_path(clash_irid,'NAME')); RAISE FOLDER_ERROR; end if; --Reset folder context jr_context.set_working_folder(NULL,context_folder); exception when OTHERS then --Handle errors, and reset folder context select nls.nls_name into el_type_name from rm_element_type_extensions nls ,I$SDD_OBJECT_VERSIONS ov where nls.for_type=ov.logical_type_id and ov.ivid=p_object_ivid; --Error reattaching %0!s %1!s rmmes.post('CDR',1054,el_type_name ,jr_name.get_CRN(p_object_ivid,'NAME')); jr_context.set_working_folder(NULL,context_folder); --Re-enable no update of checked in elements if no_checkin_upd then jr_context.enable(JR_CONTEXT.NO_CHECKIN_UPDATE); end if; RAISE; end reattach_object; --------------------------------------------------------------------------- -- IS_ORPHAN -- find out if object has any owning container in repository -- Returns 'Y' or 'N' and is callable from SQL --------------------------------------------------------------------------- function is_orphan(object_irid in number) return varchar2 is dummy number; return_val varchar2(1); begin select count(*) into dummy from I$SDD_FOLDER_MEMBERS fm ,I$SDD_OBJECT_VERSIONS ov where ov.wastebasket='N' and ov.ivid=fm.parent_ivid and fm.member_object=object_irid and fm.ownership_flag='Y'; if dummy > 0 then --Object is not an orphan return_val := 'N'; else --Object might be root folder... select count(*) into dummy from I$SDD_FOLDERS fol where fol.irid=object_irid and fol.root_flag='Y'; if dummy > 0 then --Object is a root folder return_val := 'N'; else --Object might be a configuration... select count(*) into dummy from I$SDD_CONFIGURATIONS cfg where cfg.irid=object_irid; if dummy>0 then --Object is a configuration return_val := 'N'; else --Object is an orphan return_val := 'Y'; end if;--Config end if; --Root folder end if; --Orphan return return_val; end; --------------------------------------------------------------------------- -- find out whether an object is bound in current context -- TODO: this should throw with an invalid IRID --------------------------------------------------------------------------- function is_bound( object object_irid -- the object to be queried ) return boolean is -- {{ dummy integer; begin select 1 into dummy from sdd_folder_members fm where is_bound.object=fm.member_object; return true; exception when no_data_found then return false; end is_bound; --}} --------------------------------------------------------------------------- -- just like bind, but for folders --------------------------------------------------------------------------- procedure bind_context( folder folder_handle -- the folder to be bound ,context_folder folder_handle default null -- context folder ,name_in_context name_atom default null -- name in context ) is -- {{ folder_irid object_irid; begin select irid into folder_irid from sdd_folders where folder = irid; bind(folder_irid, name_in_context); end bind_context; -- }} --------------------------------------------------------------------------- -- just like unbind, but for folders --------------------------------------------------------------------------- procedure unbind_context( folder folder_handle -- the folder to be unbound ) is -- {{ folder_irid object_irid; begin select irid into folder_irid from sdd_folders where folder = irid; unbind(folder_irid); end unbind_context; -- }} --------------------------------------------------------------------------- -- just like unbind, but for folders --------------------------------------------------------------------------- procedure delete_context( folder folder_handle -- the folder to be deleted ) is -- {{ begin delete from sdd_folders where irid = folder; end delete_context; -- }} --------------------------------------------------------------------------- -- just like rebind, but for folders --------------------------------------------------------------------------- procedure rebind_context( folder folder_handle -- the folder to be rebound ,context_folder folder_handle default null -- context folder ,name_in_context name_atom default null -- name in context ) is -- {{ folder_irid object_irid; begin select irid into folder_irid from sdd_folders where folder = irid; rebind(folder_irid, context_folder, name_in_context); end rebind_context; -- }} --------------------------------------------------------------------------- -- resolve -- Given a string, search a given context -- for an object, and return it --------------------------------------------------------------------------- function resolve( fullnamestring max_string -- the search string ,context_folder folder_handle default null -- context folder ) return object_irid -- the irid of the found object is the_object object_irid; the_fullname repos_name; the_context_folder folder_handle; immediate_context folder_handle; begin -- Deal with the special case of root context if context_folder is null then the_context_folder := get_root_context; else the_context_folder := context_folder; end if; the_fullname := parse_fullnamestring(fullnamestring); immediate_context := resolve_context(the_fullname.components, the_context_folder); trace('Immediate_context is: ''' || immediate_context || ''''); the_object := resolve_simplename(the_fullname.basename, the_fullname.extension, immediate_context); return the_object; end; --------------------------------------------------------------------------- -- resolve_context --------------------------------------------------------------------------- function resolve_context( components name_list -- list of contexts ,context_folder folder_handle default null -- context folder ) return folder_handle -- the found folder is this_context_folder folder_handle; next_context_folder folder_handle; begin -- {{ -- Deal with the special case of root context if context_folder is null then this_context_folder := get_root_context; else this_context_folder := context_folder; end if; next_context_folder := this_context_folder; for i in 1 .. components.count loop -- {{ select fo.irid into next_context_folder from sdd_folders fo, sdd_folder_members fm where this_context_folder = fm.folder_reference and fm.member_object = fo.irid and fo.name = components(i); trace('This: ''' || this_context_folder || ''' Next: ''' || next_context_folder || ''''); this_context_folder := next_context_folder; end loop; -- }} -- OK we're now at the bottom of the chain -- and voila, that's the answer! return next_context_folder; end resolve_context; -- }} --------------------------------------------------------------------------- -- resolve_simplename -- searches one level deep in a given context for an object -- with this name -- TODO: parameterise the bodysep - should be other than '.' --------------------------------------------------------------------------- function resolve_simplename( basename name_atom ,extension name_atom ,context_folder folder_handle default null -- context folder ) return object_irid -- the irid of the found object is -- {{ root_context_folder number; whole_simplename max_string; the_object object_irid; the_context_folder folder_handle; begin -- Deal with the special case of root context if context_folder is null then the_context_folder := get_root_context; else the_context_folder := context_folder; end if; begin -- {{ -- Search for the basename.extension pair whole_simplename := basename || default_body_sep || extension; select ov.irid into the_object from sdd_object_versions ov, sdd_folder_members fm, rm_sql_tables rtabs where -- The object must be inside this context folder the_context_folder = fm.folder_reference and fm.member_object = ov.irid and ov.table_irid = rtabs.irid and (( -- Object whose extension comes from the metadata whole_simplename = ov.name || default_body_sep || rtabs.extension ) or ( -- Object with embedded extension inside the name whole_simplename = ov.name )) ; exception when no_data_found then raise_application_error(-20030, 'Name: ''' || whole_simplename || ''' not found'); end; -- }} return the_object; end resolve_simplename; -- }} --------------------------------------------------------------------------- -- get_root_context -- Searches the current configuration (workarea) -- for a folder of the given name which has no parents -- fails if there are many of them, or zero --------------------------------------------------------------------------- function get_root_context( context_name name_atom default null -- name of root folder ) return folder_handle -- handle of root context is -- {{ the_context number; begin if context_name is not null then select irid into the_context from sdd_folders where name = context_name and irid not in (select fo.irid from sdd_folders fo, sdd_folder_members fm where fo.irid = fm.member_object); else select irid into the_context from sdd_folders where name is null and irid not in (select fo.irid from sdd_folders fo, sdd_folder_members fm where fo.irid = fm.member_object); end if; trace('root_context handle '|| the_context || ' found'); return the_context; exception when no_data_found then raise e_rootfolder_not_found; end get_root_context; -- }} --------------------------------------------------------------------------- -- new_context -- Create a named folder and return the handle --------------------------------------------------------------------------- function new_context( folder_name name_atom ) return folder_handle -- handle of created folder is -- {{ new_handle number; begin -- CHANGED BY ALEX WATTS 16/6/98 TO SELECT THE FOLDER HANDLE FROM THE TABLE -- SINCE IT IS NOT THE SAME AS IRID AND CREATED BY THE INSTEAD TRIGGER -- ON SDD_FOLDER_MEMBERS insert into sdd_folders (name, owning_user) values (folder_name, USER); select max(irid) into new_handle from sdd_folders where name = folder_name; return new_handle; end new_context; -- }} --------------------------------------------------------------------------- -- get_fullname -- Given an object identifier, find out its name -- by walking the folder containership - return it as a string --------------------------------------------------------------------------- function get_fullname( object object_irid ) return max_string is -- {{ the_fullnamestring max_string; the_fullname repos_name; the_table_name rm_sql_tables.table_name%type; the_table_extension rm_sql_tables.extension%type; begin -- this will return an absolute name -- TODO: logic error here - in fact is a relative name - to root! the_fullname.isabsolute := false; -- populate the basename select name into the_fullname.basename from sdd_object_versions where object = irid; -- populate the extension - either from rm_sql_tables or from -- the instance specific "extension" column in the case -- of files -- TODO: metadata drive the existence of an instance level -- extension oveiride -- Get hold of the type name and generic extension for this instance select rtabs.table_name, rtabs.extension into the_table_name, the_table_extension from sdd_object_versions ov, rm_sql_tables rtabs where object=ov.irid and rtabs.irid=ov.table_irid; -- hard code the instance level switch to be FILES -- and a special case for sdd_folders -- TODO: optimize this - move the query to -- a package init routine if (the_table_name = 'SDD_FILES') or (the_table_name = 'SDD_FOLDERS') then the_fullname.extension := ''; else the_fullname.extension := the_table_extension; end if; -- Walk the folder_member containership hierarchy -- until a root folder is reached. -- TODO: this is right shabby - having to reverse -- all the data at the end - do it differently declare -- {{ name_component_search current_object_irid number := object; i pls_integer := 0; parent_folder_handle number; temp name_atom; reverse_components name_list; num_components pls_integer; begin reverse_components := name_list(); loop begin select folder_reference into parent_folder_handle from sdd_folder_members where member_object = current_object_irid; exception when no_data_found then parent_folder_handle := null; end; exit when parent_folder_handle is null; -- we have a parent folder, so add its name to -- the NameComponents list, make it current -- and loop reverse_components.extend; i := i + 1; select irid, name into current_object_irid, reverse_components(i) from sdd_folders fo where parent_folder_handle = fo.irid; end loop; -- OK - we now have all the name components -- in reverse order! reverse them into the real structure num_components := reverse_components.count; if num_components > 0 then for i in 1..num_components loop the_fullname.components.extend; the_fullname.components(i) := reverse_components(num_components - i +1); end loop; end if; end; -- }} name_component_search -- Now have a fully populated structured name -- so convert it to a string the_fullnamestring := build_fullnamestring(the_fullname); return the_fullnamestring; end get_fullname; -- }} --------------------------------------------------------------------------- -- parse_fullnamestring -- given a string like /hello/world/foo.cpp -- parse it out and return a PL/SQL structure for easier manipulating --------------------------------------------------------------------------- function parse_fullnamestring( fullnamestring max_string ,comp_sep char default default_comp_sep ,body_sep char default default_body_sep ) return repos_name is -- {{ the_fullname repos_name; len pls_integer; idot pls_integer; islash pls_integer; i pls_integer := 0; components_string max_string; begin the_fullname.components := name_list(); len := length(fullnamestring); idot := instr(fullnamestring, body_sep, -1); islash := instr(fullnamestring, comp_sep, -1); -- Starting from the far end, extract the extension if idot = 0 then the_fullname.extension := null; idot := len + 1; else the_fullname.extension := substr(fullnamestring, idot+1, len); end if; -- Starting from the far end, search for first comp_sep for body the_fullname.basename := substr(fullnamestring, islash+1, idot-islash-1); components_string := substr(fullnamestring,1,islash); -- components_string is '?foo/bar/' -- check to see if this is a rootname if substr(components_string,1,1) = comp_sep then components_string := substr(components_string,2,len); the_fullname.isabsolute := true; else the_fullname.isabsolute := false; end if; -- components_string is 'foo/bar/' -- now consume the components string from left to right loop trace(components_string); exit when components_string is null; -- search for the first slash islash := instr(components_string,comp_sep,1); -- dump the component name into the array the_fullname.components.extend; i := i + 1; the_fullname.components(i) := substr(components_string,1,islash-1); -- otherwise trim the string and loop components_string := substr(components_string, islash+1, len); -- TODO: this is a temporary guard against parse errors exit when i > 20; end loop; return the_fullname; end parse_fullnamestring; -- }} --------------------------------------------------------------------------- -- build_fullnamestring -- given a repos_name structure, fleshes it out into -- a full string. --------------------------------------------------------------------------- function build_fullnamestring( fullname repos_name ,comp_sep char default default_comp_sep ,body_sep char default default_body_sep ) return max_string is -- {{ the_namestring max_string; i pls_integer := 0; begin -- if the name is an absolute it must start with a comp_sep if fullname.isabsolute then the_namestring := comp_sep; end if; -- loop through the Name components loop exit when i = fullname.Components.count(); i := i + 1; the_namestring := the_namestring || fullname.Components(i) || comp_sep; end loop; -- Now add on the basename the_namestring := the_namestring || fullname.basename; -- Special case: if the extension is null, we -- choose to *NOT* output the dot separator if fullname.extension is not null then the_namestring := the_namestring || body_sep || fullname.extension; end if; return the_namestring; end build_fullnamestring; -- }} procedure trace(message varchar2) is begin dbms_output.put_line('jr_folder: ' || message); end trace; end jr_folder; /