Thursday, November 24, 2011

Remove OAF Customization

First, list your customization to get the exact path:
begin
  jdr_utils.listdocuments('/oracle/apps/ar/hz/components/search/server',TRUE);
end;
Then, remove it:
begin
  jdr_utils.deletedocument(p_document => '/oracle/apps/ar/hz/components/search/server/customizations/site/0/HzPuiDQMSrchResultsVO');
  COMMIT;
end;

Monday, November 21, 2011

Compiling Form in R12 env

1. FTP your form to $AU_TOP/forms/US
2. Compile using:
frmcmp_batch userid=USERNAME/PASSWORD module=XXXXX.fmb output_file=XXXXX.fmx module_type=form
3. Move the fmx to the correct folder, ex
mv XXXXX.fmx $AP_TOP/forms/US/XXXXX.fmx
4. Done

Thursday, November 10, 2011

DBMS_SCHEDULER

When you back in the day wanted to schedule or run something in the backgound you used DBMS_JOB. With  the beginning of release 10g of the database new functionality was introduced to accomplish this, the DBMS_SCHEDULER.

DBMS_SCHEDULER is so much more flexible the DBMS_JOB and makes everything easier, some examples:

  • To set up your intervals you just specify the parameter repeat_interval.
    MON-FRI 22.00: repeat_interval=> 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=22;'
    Every hour, every day: repeat_interval => 'FREQ=HOURLY;INTERVAL=1'
    Every monday, 05:00: repeat_interval=> 'FREQ=DAILY; BYDAY=MON; BYHOUR=5;'
  • You will not get the problem with shifting start times that you have with DBMS_JOB.
  • Possible to create chains of jobs that are dependent of each other.
  • Possible to schedule:
     
    - Execution of host scripts.
     - E-mail notifications.
     - Execute host scripts on remote servers (requires an agent on the remote server).
     - Execute jobs on multiple databases.
  • You can create a file watcher that will let you monitor a folder for files. When new files arrives the specified job will start.
To be able to use all the functions of DBMS_SCHEDULER you need to be on 11g release 2. There is a lot of artictles about the DBMS_SCHEDULER but you can get a good overview with examples can be found here.

One of the cooler features with the DBMS_SCHEDULER is the file watcher. I will illustrate the functionality with an exampel.

Create a new user and directory
CREATE USER fw_test_usr IDENTIFIED BY test;
GRANT connect, resource, dba TO fw_test_usr;

CREATE OR REPLACE DIRECTORY demo_dir AS '/home/oracle/tmp';
GRANT read, write ON DIRECTORY demo_dir TO fw_test_usr;

CREATE OR REPLACE DIRECTORY demo_old_dir AS '/home/oracle/tmp/old';
GRANT read, write ON DIRECTORY demo_old_dir TO fw_test_usr;
The file watchers will by default check for files every 10 minutes, we will decrease that to every minute.
CONN / AS SYSDBA

BEGIN
  DBMS_SCHEDULER.set_attribute(
    'file_watcher_schedule',
    'repeat_interval',
    'freq=minutely; interval=1');
END;
/
Now, logged in as fw_test_usr we need to set up OS privilege for file access.
BEGIN
  DBMS_SCHEDULER.create_credential(
    credential_name => 'watcher_credential',
    username        => 'oracle',
    password        => 'oracle');
END;

SELECT * FROM dba_scheduler_credentials;
The next step is to create the file watcher. The file watcher is not enabled yet (enabled => FALSE).
BEGIN
  DBMS_SCHEDULER.create_file_watcher(
    file_watcher_name => 'demo_file_watcher',
    directory_path    => '/home/oracle/tmp',
    file_name         => '*.txt',
    credential_name   => 'watcher_credential',
    destination       => NULL,
    enabled           => FALSE);
END;

SELECT * FROM dba_scheduler_file_watchers;
Create a table and the procedure that will be used by the file watcher.
CREATE TABLE fw_demo_tbl_output 
 (message VARCHAR2(4000),
  row1    VARCHAR2(4000));

CREATE OR REPLACE
PROCEDURE fw_demo_proc (p_fileinfo SYS.SCHEDULER_FILEWATCHER_RESULT) AS

  v_file    utl_file.file_type;
  v_message VARCHAR2(4000);
  v_row1    VARCHAR2(4000);
BEGIN
  -- file path, name and size
  v_message := p_fileinfo.directory_path||'/'||
               p_fileinfo.actual_file_name||'('||
               p_fileinfo.file_size||')';

  -- read the first row of the file
  v_file := utl_file.fopen('DEMO_DIR', p_fileinfo.actual_file_name, 'R');
  LOOP
    BEGIN
      utl_file.get_line(v_file, v_row1);
      EXIT;
    EXCEPTION
      WHEN OTHERS THEN
        EXIT;
    END;
  END LOOP;
  utl_file.fclose(v_file);

  -- move the file to the old directory with a new name
  utl_file.frename
     (src_location  => 'DEMO_DIR',
      src_filename  => p_fileinfo.actual_file_name,
      dest_location => 'DEMO_OLD_DIR',
      dest_filename => p_fileinfo.actual_file_name||'.'||to_char(SYSDATE, 'YYMMDDHH24MISS'),
      overwrite     => FALSE);

  INSERT INTO fw_demo_tbl_output (message, row1) VALUES (v_message, v_row1);
  COMMIT;
END;
Create a Program object with a Metadata argument (what will happen when the file watcher event is raised). The program must reference the event_message to retrieve information about the file, such as it's name. The program is not enabled yet (enabled => FALSE).
BEGIN
  DBMS_SCHEDULER.create_program(
    program_name        => 'fw_demo_prog',
    program_type        => 'stored_procedure',
    program_action      => 'fw_demo_proc',
    number_of_arguments => 1,
    enabled             => FALSE);
END;

BEGIN
  DBMS_SCHEDULER.define_metadata_argument(
    program_name       => 'fw_demo_prog',
    metadata_attribute => 'EVENT_MESSAGE',
    argument_position  => 1);
END;

SELECT *
FROM dba_scheduler_programs
WHERE program_name= 'FW_DEMO_PROG'
ORDER BY 1;

SELECT *
FROM dba_scheduler_program_args
WHERE program_name = 'FW_DEMO_PROG';
Now, create the job. The job is not enabled yet (enabled => FALSE).
BEGIN
  DBMS_SCHEDULER.create_job(
    job_name        => 'fw_demo_job',
    program_name    => 'fw_demo_prog',
    event_condition => NULL,
    queue_spec      => 'demo_file_watcher',
    auto_drop       => FALSE,
    enabled         => FALSE);
END;

SELECT *
FROM dba_scheduler_jobs
WHERE job_name='FW_DEMO_JOB';
By default, the arrival of new files will be ignored if the job is already running. If you need the job to fire for each new arrival, regardless of whether the job is already running or not, set the PARALLEL_INSTANCES attribute for the job to true. The job will then be run as a lightweight job.
BEGIN
  DBMS_SCHEDULER.set_attribute('fw_demo_job','parallel_instances',TRUE);
END;
The last step is to enable everything.
BEGIN
  DBMS_SCHEDULER.enable('demo_file_watcher');
  DBMS_SCHEDULER.enable('fw_demo_prog');
  DBMS_SCHEDULER.enable('fw_demo_job');
END;
Now create some .txt files in folder /home/oracle/tmp on the server. Then wait a couple a minutes and the information sould appear in the table. The files should also have been moved to the old folder on the server.
SELECT * FROM  fw_demo_tbl_output;

javascript:void(0)