Call now: 252-767-6166  
Oracle Training Oracle Support Development Oracle Apps

 
 Home
 E-mail Us
 Oracle Articles
New Oracle Articles


 Oracle Training
 Oracle Tips

 Oracle Forum
 Class Catalog


 Remote DBA
 Oracle Tuning
 Emergency 911
 RAC Support
 Apps Support
 Analysis
 Design
 Implementation
 Oracle Support


 SQL Tuning
 Security

 Oracle UNIX
 Oracle Linux
 Monitoring
 Remote s
upport
 Remote plans
 Remote
services
 Application Server

 Applications
 Oracle Forms
 Oracle Portal
 App Upgrades
 SQL Server
 Oracle Concepts
 Software Support

 Remote S
upport  
 Development  

 Implementation


 Consulting Staff
 Consulting Prices
 Help Wanted!

 


 Oracle Posters
 Oracle Books

 Oracle Scripts
 Ion
 Excel-DB  

Don Burleson Blog 


 

 

 


 

 

 

 

 

11g PL/SQL Subprogram Inlining and Compound Triggers

Oracle 11g New Features Tips by Donald BurlesonJuly 13, 2015

Oracle 11g New Features Tips

Subprogram inlining has been around in optimizing compilers for a long time.  With the 11g database, Oracle has included this feature in PL/SQL.  Basically subprogram inlining is where the program calls a subprogram (procedure or function) and the compiler places the actual subprogram code in place of the call to that code.  Since the subprogram code is in the main code (INLINE), the overhead of calling that subprogram is saved.  This allows you to program using a modular method, producing readable, maintainable source code, while the compiler optimizes the code to make it more efficient.

If the PLSQL_OPTIMIZER_LEVEL is set to 3 the compiler will automatically try and inline subprograms.  If the PLSQL_OPTIMIZER_LEVEL is set to 2 (the default) it will not automatically try and inline subprograms.  So the PRAGMA INLINE is used to tell the optimizer to inline or not to inline depending on the setting of the optimizer level.

The PRAGMA INLINE statement is used to tell the optimizer if the following statements subprograms should be placed inline or not.

In the example below, the PARGMA INLINE is used to inline the first function call but not the second.  The PARGMA INLINE statement only effects the statement following PARGMA INLINE statement.

create or replace package inline_demo is
  procedure runtest;
end;
/

create or replace package body inline_demo as 

function newadd(n1 number) return number
as
 n11 number;
begin
  n11:= n1+n1;
  return n11;
end;

procedure runtest as 
  n2 number := 0;
begin
  n2 := 3;
  dbms_output.put('Num: '||n2);
 
PRAGMA INLINE (newadd,'YES');
  n2 := newadd(n2);
  dbms_output.put('  Num2: '||n2);
 
PRAGMA INLINE (newadd,'NO');
  n2 := newadd(n2);
  dbms_output.put_line('  Num3: '||n2);
end;

end inline_demo;
/

SQL> exec inline_demo.runtest;
Num: 3  Num2: 6  Num3: 12

PL/SQL procedure successfully completed.

The PARGMA INLINE impacts all calls in the statement that follows it. If the statement is a loop, then all calls to the subprogram in the loop is placed inline.

Inlining subprogram code is a common and powerful code optimization capability that should be used when possible.  Placing the PLSQL_OPTIMIZER_LEVEL parameter to 3 will automate the code inline process.

PL/SQL Compound Triggers

A compound trigger is a PL/SQL trigger that contains multiple actions that take place at different timing points.  The timing points for a compound trigger on a table are:

BEFORE STATEMENT  - before trigger statement executes
AFTER STATEMENT     - after the trigger statement executes
BEFORE EACH ROW    - before each row the statement impacts
AFTER EACH ROW       - after each row the statement impacts

If the compound trigger is on a view, the only timing point is:

INSTEAD OF EACH ROW

The real advantage of the compound trigger is that the trigger definition has a declaration section and variable state is maintained through each timing section from the firing of the trigger to completion.  The statements at each timing point have some restrictions.  The statement must be DML and can contain Inserting, Updating, Deleting and Applying.  If the statement at the timing point does not impact any rows, the before statement and after statement do not fire.  The compound trigger body does not have an initialization block and thus no exception block.  All exceptions must be handled in the section that raised the exception.  You cannot pass execution from one section to another using an exception handler or a GOTO statement.  The references to :OLD, :NEW or :PARENT cannot be used in the declaration section, BEFORE STATEMENT or AFTER STATEMENT.  Only the BEFORE EACH ROW section can change the :NEW value.

The order of firing within a compound trigger is defined, however like simple triggers, the order of firing of multiple triggers (compound or simple) is not guaranteed. The order of firing multiple triggers can be defined using the FOLLOWS statement.  The FOLLOWS option is explained in the next section.

Let's look at a compound trigger. The following code creates a test table and a compound trigger that fires for each timing point associated with insert, update and delete statements. The triggering actions are logged in a PL/SQL table defined in the global declaration section. The final timing point for each statement prints out the content of the PL/SQL table to show that the variable state has been maintained throughout the lifetime of the statement.

The example courtesy of Dr. Tim Hall (www.oracle-base.com)

CREATE TABLE compound_trigger_test (
  id           NUMBER,
  description  VARCHAR2(50)
);

CREATE OR REPLACE TRIGGER compound_trigger_test_trg
  FOR INSERT OR UPDATE OR DELETE ON compound_trigger_test
    COMPOUND TRIGGER 

  -- Global declaration.

  TYPE t_tab IS TABLE OF VARCHAR2(50);
  l_tab t_tab := t_tab(); 

  BEFORE STATEMENT IS

  BEGIN
    l_tab.extend;
    CASE
      WHEN INSERTING THEN
        l_tab(l_tab.last) := 'BEFORE STATEMENT - INSERT';
      WHEN UPDATING THEN
        l_tab(l_tab.last) := 'BEFORE STATEMENT - UPDATE';
      WHEN DELETING THEN
        l_tab(l_tab.last) := 'BEFORE STATEMENT - DELETE';
    END CASE;
  END BEFORE STATEMENT; 

  BEFORE EACH ROW IS
  BEGIN
    l_tab.extend;
    CASE
      WHEN INSERTING THEN
        l_tab(l_tab.last) := 'BEFORE EACH ROW - INSERT (new.id=' || :new.id ||
')';
      WHEN UPDATING THEN
        l_tab(l_tab.last) := 'BEFORE EACH ROW - UPDATE (new.id=' || :new.id ||
' old.id=' || :old.id || ')';
      WHEN DELETING THEN
        l_tab(l_tab.last) := 'BEFORE EACH ROW - DELETE (old.id=' || :old.id ||
')';
    END CASE;
  END BEFORE EACH ROW; 

  AFTER EACH ROW IS
  BEGIN
    l_tab.extend;
    CASE
      WHEN INSERTING THEN
        l_tab(l_tab.last) := 'AFTER EACH ROW - INSERT (new.id=' || :new.id ||
')';
      WHEN UPDATING THEN
        l_tab(l_tab.last) := 'AFTER EACH ROW - UPDATE (new.id=' || :new.id ||
' old.id=' || :old.id || ')';
      WHEN DELETING THEN
        l_tab(l_tab.last) := 'AFTER EACH ROW - DELETE (old.id=' || :old.id ||
')';
    END CASE;
  END AFTER EACH ROW; 

  AFTER STATEMENT IS
  BEGIN
    l_tab.extend;
    CASE
      WHEN INSERTING THEN
        l_tab(l_tab.last) := 'AFTER STATEMENT - INSERT';
      WHEN UPDATING THEN
        l_tab(l_tab.last) := 'AFTER STATEMENT - UPDATE';
      WHEN DELETING THEN
        l_tab(l_tab.last) := 'AFTER STATEMENT - DELETE';
    END CASE;   

    FOR i IN l_tab.first .. l_tab.last LOOP
      DBMS_OUTPUT.put_line(l_tab(i));
    END LOOP;
    l_tab.delete;
  END AFTER STATEMENT; 

END compound_trigger_test_trg;
/

By issuing several insert, update and delete statements against the test table we can see that the compound trigger is working as expected.

SQL> SET SERVEROUTPUT ON
SQL> INSERT INTO compound_trigger_test VALUES (1, 'ONE');
BEFORE STATEMENT - INSERT
BEFORE EACH ROW - INSERT (new.id=1)
AFTER EACH ROW - INSERT (new.id=1)
AFTER STATEMENT - INSERT 

1 row created.

SQL> INSERT INTO compound_trigger_test VALUES (2, 'TWO');
BEFORE STATEMENT - INSERT
BEFORE EACH ROW - INSERT (new.id=2)
AFTER EACH ROW - INSERT (new.id=2)
AFTER STATEMENT - INSERT 

1 row created.

SQL> UPDATE compound_trigger_test SET id = id;
BEFORE STATEMENT - UPDATE
BEFORE EACH ROW - UPDATE (new.id=2 old.id=2)
AFTER EACH ROW - UPDATE (new.id=2 old.id=2)
BEFORE EACH ROW - UPDATE (new.id=1 old.id=1)
AFTER EACH ROW - UPDATE (new.id=1 old.id=1)
AFTER STATEMENT - UPDATE

2 rows updated.

SQL> DELETE FROM compound_trigger_test;
BEFORE STATEMENT - DELETE
BEFORE EACH ROW - DELETE (old.id=2)
AFTER EACH ROW - DELETE (old.id=2)
BEFORE EACH ROW - DELETE (old.id=1)
AFTER EACH ROW - DELETE (old.id=1)
AFTER STATEMENT - DELETE

2 rows deleted. 

SQL>

One of the real advantages of a compound trigger is to use the FOR EACH ROW statement to capture changes and load them into a PL/SQL table, then use the AFTER STATEMENT statement to bulk load the changes into another table.  Using simple triggers, you would have to reference a package to load the data and then execute the bulk load.  With a compound trigger these operations are internal to the trigger.

 

This is an excerpt from the new book Oracle 11g New Features: Expert Guide to the Important New Features by John Garmany, Steve Karam, Lutz Hartmann, V. J. Jain, Brian Carr.

You can buy it direct from the publisher for 30% off.

 

 
��  
 
 
Oracle Training at Sea
 
 
 
 
oracle dba poster
 

 
Follow us on Twitter 
 
Oracle performance tuning software 
 
Oracle Linux poster
 
 
 

 

Burleson is the American Team

Note: This Oracle documentation was created as a support and Oracle training reference for use by our DBA performance tuning consulting professionals.  Feel free to ask questions on our Oracle forum.

Verify experience! Anyone considering using the services of an Oracle support expert should independently investigate their credentials and experience, and not rely on advertisements and self-proclaimed expertise. All legitimate Oracle experts publish their Oracle qualifications.

Errata?  Oracle technology is changing and we strive to update our BC Oracle support information.  If you find an error or have a suggestion for improving our content, we would appreciate your feedback.  Just  e-mail:  

and include the URL for the page.


                    









Burleson Consulting

The Oracle of Database Support

Oracle Performance Tuning

Remote DBA Services


 

Copyright © 1996 -  2020

All rights reserved by Burleson

Oracle ® is the registered trademark of Oracle Corporation.