Houston – we have deleted all SYS DBMS_SCHEDULER Jobs !

Bad, bad PL/SQL….

A customer of me has executed a simple script to cleanup DBMS_SCHEDULER jobs and programs for an application. Unfortunately he did as user SYS. The content of the SQL script:

BEGIN
  FOR JOB IN (SELECT * FROM USER_SCHEDULER_JOBS) LOOP
    DBMS_SCHEDULER.DROP_JOB(JOB_NAME => JOB.JOB_NAME, FORCE => TRUE);
  END LOOP;

  FOR PROG in (select * from USER_SCHEDULER_PROGRAMS) LOOP
    DBMS_SCHEDULER.DROP_PROGRAM(PROGRAM_NAME => PROG.PROGRAM_NAME, FORCE => TRUE);
  END LOOP; 
END;
/

All the Oracle internal maintenance jobs and programs like the AUTO_SPACE_ADVISOR_PROG, GATHER_STATS_PROG, FILE_WATCHER_PROGRAM are deleted.

SQL> SELECT owner,job_name
  2  FROM dba_scheduler_jobs
  3  ORDER by job_name;

no rows selected
SQL> SELECT owner,program_name
  2  FROM dba_scheduler_programs
  3  ORDER by program_name;

no rows selected

On a 12.1.0.2 single instance database on Linux are per default 19 DBA_SCHEDULER_JOBS and 10 DBA_SCHEDULER_PROGRAMS pre-configured.

Oracle has a MOS note called  How to Rebuild DBMS_SCHEDULER Default Jobs and Autotasks (Doc ID 2089546.1) – but this note is old and incomplete. It does not help to rebuild all the jobs and programs in a 12.1.0.2 database.

After some discussions with My Oracle Support, this way here works to rebuild the jobs. Unfortunately it’s an “offline” task, you have to restart your database in UPGRADE mode. But it works.

1. Make sure that you have a Backup of your Database

2. Restart the Database in UPGRADE Mode

SQL> shutdown immediate
SQL> startup upgrade

3. Run these Commands as SYSDBA in Order to recreate the missing Scheduler Jobs

SQL> spool fix_cat_logfile.txt
SQL> @?/rdbms/admin/catalog.sql
SQL> @?/rdbms/admin/catproc.sql
SQL> @?/rdbms/admin/utlrp.sql
SQL> @?/rdbms/admin/utlrp.sql
SQL> @?/rdbms/admin/utlrp.sql
SQL> spool off

All jobs except XMLDB_NFS_CLEANUP_JOB are re-created now. To rebuild the XMLDB_NFS_CLEANUP_JOB you can execute this command as user SYS in SQL*Plus. It’s just an extract from the file ?/rdbms/admin/xdbu102.sql which creates the required job during the regular instance creation process.

DECLARE
  c number;
BEGIN
  select count(*) into c
  from ALL_SCHEDULER_JOB_CLASSES
  where JOB_CLASS_NAME = 'XMLDB_NFS_JOBCLASS';

  if c = 0 then
    dbms_scheduler.create_job_class(
      job_class_name  => 'SYS.XMLDB_NFS_JOBCLASS',
      logging_level   => DBMS_SCHEDULER.LOGGING_FAILED_RUNS);
  end if;

  select count(*) into c
  from ALL_SCHEDULER_JOBS
  where JOB_NAME = 'XMLDB_NFS_CLEANUP_JOB';

  if c = 0 then
    dbms_scheduler.create_job(
        job_name => 'SYS.XMLDB_NFS_CLEANUP_JOB' ,
        job_type=>'STORED_PROCEDURE',
        job_action=>'xdb.dbms_xdbutil_int.cleanup_expired_nfsclients',
        job_class=>'SYS.XMLDB_NFS_JOBCLASS',
        repeat_interval=>'Freq=minutely;interval=5');
  end if;
  execute immediate 'delete from noexp$ where name = :1' using 'XMLDB_NFS_JOBCLASS';
  execute immediate 'insert into noexp$ (owner, name, obj_type) values(:1, :2, :3)' using 'SYS', 'XMLDB_NFS_JOBCLASS', '68';
end;
/

4. Restart the Database

SQL> shutdown immediate
SQL> startup

5. Run these Queries to verify invalid Objects

SQL> SELECT comp_name, version, status FROM dba_registry;

COMP_NAME                                VERSION                        STATUS
---------------------------------------- ------------------------------ ------------
Oracle XML Database                      12.1.0.2.0                     VALID
Oracle Database Catalog Views            12.1.0.2.0                     VALID
Oracle Database Packages and Types       12.1.0.2.0                     VALID

3 rows selected.

SQL> SELECT substr(object_name,1,40) object_name,substr(owner,1,15) owner,object_type
  2  FROM dba_objects
  3  WHERE status='INVALID'
  4  ORDER BY owner, object_type;

no rows selected

6. Verify that DBMS_SCHEDULER Jobs are back

SQL> SELECT owner,job_name
  2  FROM dba_scheduler_jobs
  3  ORDER BY job_name;

OWNER                  JOB_NAME
---------------------- ------------------------------
SYS                    BSLN_MAINTAIN_STATS_JOB
SYS                    CLEANUP_NON_EXIST_OBJ
SYS                    CLEANUP_ONLINE_IND_BUILD
SYS                    CLEANUP_ONLINE_PMO
SYS                    CLEANUP_TAB_IOT_PMO
SYS                    CLEANUP_TRANSIENT_PKG
SYS                    CLEANUP_TRANSIENT_TYPE
SYS                    DRA_REEVALUATE_OPEN_FAILURES
SYS                    FGR$AUTOPURGE_JOB
SYS                    FILE_SIZE_UPD
SYS                    FILE_WATCHER
SYS                    HM_CREATE_OFFLINE_DICTIONARY
SYS                    LOAD_OPATCH_INVENTORY
SYS                    ORA$AUTOTASK_CLEAN
SYS                    PMO_DEFERRED_GIDX_MAINT_JOB
SYS                    PURGE_LOG
SYS                    RSE$CLEAN_RECOVERABLE_SCRIPT
SYS                    SM$CLEAN_AUTO_SPLIT_MERGE
SYS                    XMLDB_NFS_CLEANUP_JOB

19 rows selected.

7. Verify DBMS_SCHEDULER Programs are back

SQL> SELECT owner,program_name
  2  FROM dba_scheduler_programs
  3  ORDER by program_name;

OWNER                     PROGRAM_NAME
------------------------- ------------------------
SYS                       AQ$_PROPAGATION_PROGRAM
SYS                       AUTO_SPACE_ADVISOR_PROG
SYS                       AUTO_SQL_TUNING_PROG
SYS                       BSLN_MAINTAIN_STATS_PROG
SYS                       FILE_WATCHER_PROGRAM
SYS                       GATHER_STATS_PROG
SYS                       HS_PARALLEL_SAMPLING
SYS                       ORA$AGE_AUTOTASK_DATA
SYS                       PMO_DEFERRED_GIDX_MAINT
SYS                       PURGE_LOG_PROG

10 rows selected.

Summary

Deleting the SYS DBMS_SCHEDULER jobs is one of these mistakes which can be easily repaired. But during the rebuild action, the database is not available for the end users and this is bad. I’m looking forward that there will be an online solution available maybe in the future.

Another approach could be to execute a FLASHBACK QUERY against the dba_source view to get the DDL for the missing jobs and programs before the delete action. But this has to be tested first.