PL/SQLintermediate

Database Triggers in EBS Customizations

Explain the appropriate and risky uses of database triggers within an Oracle EBS environment

A trigger on an EBS base table is almost always the wrong answer, and knowing why is the point of this topic.

Adding a custom trigger to a seeded EBS table is like splicing your own wiring into a building's fire alarm system — it might work today, but the next time the fire department (Oracle patch) services the panel, your unofficial wiring could get ripped out or cause a false alarm.

Key Concepts

1
The standard trap: "would you add a trigger on AP_INVOICES_ALL for custom validation?"No. Three reasons, and they are all concrete.
AP_INVOICES_ALL
2
Oracle's own triggers already fire there. Your trigger's order relative to them is not something you control, so your validation may run before or after logic it depends on.
3
Mutating table errors. A row-level trigger that queries the table it is firing on raises ORA-04091. Validation that needs to look at other rows of the same table — "no more than three open invoices per supplier" — hits this immediately.
ORA-04091
4
Patches. Oracle changes seeded tables and their triggers. A custom trigger is not in Oracle's inventory, so nothing warns you when it breaks, and revalidating every custom trigger is added to every upgrade.
5
What to use instead, in Oracle's own order of preference:
6
    API user hooks     where the API provides an extension point
    Business Events    react to something that happened, in workflow
    Forms Personalization  UI-level validation
    CUSTOM.pll         Forms-level logic across screens
7
Each of these is a place Oracle intends you to put code, so it survives patching and has a defined firing point.
8
Triggers on your own custom tables are fine, following ordinary practice: keep the logic short, avoid querying the triggering table, and do not chain triggers into each other.
9
Compound triggers solve the mutating table problem where a trigger genuinely is right. They combine the timing points in one object with shared state:
10
    CREATE OR REPLACE TRIGGER trg_example
    FOR INSERT OR UPDATE ON xx_custom_table
    COMPOUND TRIGGER
      TYPE t_ids IS TABLE OF NUMBER;
      g_ids t_ids := t_ids();
11
      AFTER EACH ROW IS BEGIN
        g_ids.EXTEND; g_ids(g_ids.COUNT) := :NEW.id;     -- collect
      END AFTER EACH ROW;
12
      AFTER STATEMENT IS BEGIN
        -- now safe to query the table
      END AFTER STATEMENT;
    END;
13
Collect the affected ids row by row, then do the work once the statement has finished and the table is no longer mutating.
14
The governance point. EBS customisation has an order of preference — configuration, then supported extension points, then custom objects, and never modifying seeded code. A trigger on a seeded table sits outside that hierarchy, which is why the answer is no even when it would work.
15
What the interviewer is probing.1. "When is a trigger the wrong answer in EBS?" Probing: judgement. Stalls: "Never." *Moves up:* almost always on seeded tables — it is unsupported, invisible to the next person, and a patch can drop or recreate the table.
16
2. "What is the supported alternative?" Probing: the knowledge. Stalls: "Nothing." *Moves up:* business events and subscriptions, CUSTOM.pll, form personalisation, or a public API — all survive patching.
17
3. "What is a mutating table error?" Probing: the classic. Stalls: "A lock." Moves up: a row-level trigger querying the table being modified, which the compound trigger or a statement-level approach resolves.
18
4. "If a trigger is unavoidable, what do you do?" Probing: the pragmatism. Stalls: "Just write it." Moves up: keep it tiny, put the logic in a package, document it in the custom object register, and retest it after every patch.