How to Base a Block on Transactional Triggers in Oracle Forms

When rows exist in no table: an Oracle Forms 14.1.2 block on transactional triggers that computes a doctor's slots in ON-SELECT and ON-FETCH.

Some rows exist in no table. A doctor's free time slots are computed from the working day and the appointments; other data may come from a web service or a system SQL cannot reach. For such rows, Oracle Forms lets triggers do what Forms would otherwise do with SQL.

This guide builds a block on transactional triggers in Oracle Forms 14.1.2 that shows a doctor's day in half-hour slots. It covers the triggers that replace querying and saving, CREATE_QUERIED_RECORD, and the RECORDS_TO_FETCH block property.

Sample Form for This Guide

The examples and screenshots use the sample form CH27_SLOTS from the Oracle Forms code repository on GitHub. Download it, open it in Forms Builder, and connect as CAREWELL to follow along.

FormFileWhat it shows
CH27_SLOTSforms/ch27/ch27_slots.fmbA doctor's day in half-hour slots, computed by code

The forms run against the CareWell Clinic sample schema, which you install first.

Transactional Triggers at a Glance

With the block's Query Data Source Type set to Transactional triggers, these triggers replace Forms' own processing:

TriggerReplacesWhat to do in it
ON-SELECTOpening the queryPrepare the rows.
ON-FETCHFetchingCreate records with CREATE_QUERIED_RECORD and fill them, up to GET_BLOCK_PROPERTY(block, RECORDS_TO_FETCH) at each call. Forms calls it again as the user scrolls, until a call creates no record.
ON-COUNTCount QueryReturn the number of rows.
ON-LOCK, ON-INSERT, ON-UPDATE, ON-DELETE, ON-COMMITThe statements of a saveWrite the changes, with DML Data Target Type also set to Transactional triggers.

Other block data sources are compared in how to base a block on stored procedures, and a read-only query block in how to base a block on a FROM clause query.

Example: a Doctor's Time Slots

The sample slots form shows a doctor's day in half-hour slots, and who is booked in each.

Oracle Forms block on transactional triggers showing a doctor's half-hour slots
Dr. Sara Nair's slots on 26 October 2026.

A Package That Computes the Slots

A package of the form computes the slots one at a time.

Program unit SLOTS (package specification):

package slots is
  -- the half-hour slots of a doctor's day, for a block on transactional triggers
  procedure open_day(p_doctor_id number, p_day date);
  function next_slot(p_start out date, p_patient out varchar2) return boolean;
end slots;

Program unit SLOTS (package body):

package body slots is
  g_doctor number;
  g_next   date;                                  -- the next slot to return
  g_end    date;                                  -- the end of the day

  procedure open_day(p_doctor_id number, p_day date) is
  begin
    g_doctor := p_doctor_id;
    g_next   := trunc(p_day) + 9 / 24;            -- 09:00
    g_end    := trunc(p_day) + 17 / 24;           -- 17:00
  end open_day;

  function next_slot(p_start out date, p_patient out varchar2) return boolean is
  begin
    if g_next is null or g_next >= g_end then
      return false;
    end if;
    p_start := g_next;
    select min(p.first_name || ' ' || p.last_name) into p_patient
      from appointments a, patients p              -- no ANSI join in Forms PL/SQL
     where p.patient_id = a.patient_id
       and a.doctor_id = g_doctor
       and a.status <> 'CANCELLED'
       and a.appt_start < g_next + 30 / 1440
       and a.appt_start + a.duration_min / 1440 > g_next;
    g_next := g_next + 30 / 1440;
    return true;
  end next_slot;
end slots;

The join is written in the WHERE clause, because the PL/SQL of Forms does not accept ANSI joins.

ON-SELECT Starts the Day

Example (ON-SELECT trigger on the SLOTS block):

slots.open_day(:ctl.doctor_id, :ctl.day);

ON-FETCH Creates the Records

Example (ON-FETCH trigger on the SLOTS block):

declare
  v_start   date;
  v_patient varchar2(61);
begin
  for i in 1 .. get_block_property('SLOTS', records_to_fetch) loop   -- rows Forms asks for
    exit when not slots.next_slot(v_start, v_patient);
    create_queried_record;                          -- a new record, status QUERY
    :slots.slot_start := v_start;
    :slots.booked_for := nvl(v_patient, 'Free');
  end loop;
end;

The appointment of Kavya Fernandes at 11:45, for thirty minutes, covers two slots, 11:30 and 12:00, which is why both show her name.

CREATE_QUERIED_RECORD and RECORDS_TO_FETCH

CREATE_QUERIED_RECORD creates a record with the status QUERY, as if it had been fetched. The user can scroll, and nothing counts as a change: Save answered FRM-40401: No changes to save.

:SYSTEM.RECORDS_TO_FETCH, which older code uses, does not compile in Forms 14.1.2; it fails with "bad bind variable". The block property RECORDS_TO_FETCH, read with GET_BLOCK_PROPERTY as in the trigger above, replaces it. Block properties are covered in SET_BLOCK_PROPERTY in Oracle Forms.

A Query-Only Block

The slots block is query-only, so its DML Data Target Type is None. With Transactional triggers as the DML target and no ON- triggers for the save, the compiler warned FRM-30199: Transactional triggers do not exist for this block.

If users must change such rows, set DML Data Target Type to Transactional triggers and write ON-LOCK, ON-INSERT, ON-UPDATE, ON-DELETE, and ON-COMMIT as needed. That is the price of this data source: you write everything, fetching, counting, locking, and saving, yourself.

Conclusion

A block on transactional triggers in Oracle Forms gets its rows from code instead of SQL. ON-SELECT prepares the rows, ON-FETCH creates them with CREATE_QUERIED_RECORD up to the RECORDS_TO_FETCH block property per call, and ON-COUNT answers Count Query, while ON-LOCK, ON-INSERT, ON-UPDATE, ON-DELETE, and ON-COMMIT handle saving when the block allows changes. Use it for rows that exist in no table, and keep a query-only block's DML Data Target Type at None.

Get more Vinish.dev tutorials on Google

See my articles more often when you search Google.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted