Exception object

An Exception object you can pass around between procedures. It was a bit of an experiment and I haven't found a real use for it yet, but maybe that's just because I've been working on warehouse systems for a while. Let me know if you find a use for it!

-- EXCEPTION object type
-- William Robertson 2003, www.williamrobertson.net

create or replace type exception_ot as object
( message     varchar2(32767)
, error_code  integer
, module      varchar2(30)
, action      varchar2(100)
, os_logdir   varchar2(80)
, os_logfile  varchar2(70)
, raised      timestamp
, member procedure include_text
  ( p_word1              varchar2 default null
  , p_word2              varchar2 default null
  , p_word3              varchar2 default null )
, member procedure log
  ( p_log_to_database_yn varchar2 default 'Y'
  , p_log_to_file_yn     varchar2 default 'N'
  , p_send_mail_yn       varchar2 default 'N' )
, member procedure raise
  ( p_log_to_database_yn varchar2 default 'N'
  , p_log_to_file_yn     varchar2 default 'N'
  , p_send_mail_yn       varchar2 default 'N' )
, constructor function exception_ot
  ( p_message            varchar2
  , p_error_code         integer  default -20000
  , p_module             varchar2 default null
  , p_action             varchar2 default null
  , p_logdir             varchar2 default null
  , p_logfile            varchar2 default null )
  return self as result
, member procedure print )
/

show errors

create or replace type body exception_ot
as
   member procedure include_text
      ( p_word1              varchar2 default null
      , p_word2              varchar2 default null
      , p_word3              varchar2 default null )
   is
   begin
      message := replace(replace(replace(message,'[1]',p_word1),'[2]',p_word2),'[3]',p_word3);
   end;


   member procedure log
      ( p_log_to_database_yn varchar2 default 'Y'
      , p_log_to_file_yn     varchar2 default 'N'
      , p_send_mail_yn       varchar2 default 'N' )
   is
   begin
      if upper(substr(p_log_to_database_yn,1,1)) = 'Y' then
         logger.write(message, module, action);
      end if;

      if upper(substr(p_log_to_file_yn,1,1)) = 'Y' then
         logger.write(message, module, action);
      end if;

      if upper(substr(p_send_mail_yn,1,1)) = 'Y' then
         logger.write(message, module, action);
      end if;
   end;


   member procedure raise
      ( p_log_to_database_yn varchar2 default 'N'
      , p_log_to_file_yn     varchar2 default 'N'
      , p_send_mail_yn       varchar2 default 'N' )
   is
   begin
      raise_application_error
      ( nvl(error_code,-20000)
      , message
      , true );
   end;


   constructor function exception_ot
      ( p_message            varchar2
      , p_error_code         integer  default -20000
      , p_module             varchar2 default null
      , p_action             varchar2 default null
      , p_logdir             varchar2 default null
      , p_logfile            varchar2 default null )
      return self as result
   is
      v_module varchar2(30);
      v_action varchar2(100);
      v_dummy  pls_integer;
   begin
      message    := p_message;
      error_code := nvl(p_error_code,-20000);

      if p_logdir is not null then
         begin
            select directory_name into os_logdir
            from   all_directories
            where  p_logdir in (directory_name, directory_path)
            order by
                   decode(p_logdir, directory_name, 1,2);

            begin
               select 1 into v_dummy
               from   user_tab_privs_recd
               where  table_name = self.os_logdir
               and    privilege = 'WRITE';
            exception
               when no_data_found then
                  raise_application_error
                  ( -20999
                  , 'user ' || user || ' lacks write permission to directory "' || p_logdir || '".' );
            end;
         exception
            when no_data_found then
               raise_application_error
               ( -20999
               , 'No such directory "' || p_logdir ||
                 '" defined in database.' );
         end;
      end if;

      os_logfile := p_logfile;

      raised     := systimestamp;

      if p_module is null
      or p_action is null
      then
         dbms_application_info.read_module(v_module, v_action);
         module := nvl(p_module,v_module);
         action := coalesce(p_action,v_action,'Unknown');
      end if;
      return;
   end;


   member procedure print
   is
   begin
      echo(error_code || ': ' || message);
   end;
end;
/

show errors

create or replace package error
as
   e_general constant exception_ot := exception_ot('An error occurred', -20001);
   e_no_such constant exception_ot := exception_ot('No such [1]', -20002);
   e_job     constant exception_ot := exception_ot('Job submit error', -20003);
end error;
/

prompt demo exception_ot:

create or replace procedure test_exception
   ( p_test varchar2 )
as
   e_no_such_thing exception_ot := error.e_no_such;
   v_dummy varchar2(1);
begin
   select dummy into v_dummy from dual where dummy = p_test;
exception
   when no_data_found then
      -- e_no_such_thing.message := sqlerrm;
      e_no_such_thing.include_text('dummy "' || p_test || '"');
      e_no_such_thing.print();
      e_no_such_thing.raise();
end;
/

PROMPT Success:
exec test_exception('X')

PROMPT Failure:
exec test_exception('Y')