Post on 06-Apr-2018
transcript
8/2/2019 9i Database Triggers
1/25
NNEWEW OORACLERACLE99II DDATABASEATABASE TTRIGGERSRIGGERS
Joe Trezzo, TUSC
INTRODUCTIONOracle8i introduced an important expansion of database triggers that has been enhanced witheach new version. This important expansion extended the use of database triggers beyondtables to allow more flexibility and functionality to be integrated into your databaseenvironment and applications. From Oracle 8.1 to Oracle 9.2, this expansion has continued andthe power has increased.
Most DBAs and developers are unaware or have not taken advantage of these new databasetriggers, and therefore, the intent of this paper is to provide insight into these new triggers to
ensure that they are understood and used to their fullest by both DBAs and developers. Thispaper concentrates on identifying the new database triggers and associated components ofthese new triggers. This paper does not focus on database triggers at the table level.
The following topics are covered in this paper:
Overview of Database Triggers
Creation of Database Triggers
Security of Database Triggers
Enabling and Disabling Database Triggers
New Database Triggers
Database System Events
DDL/Client Events
Event Attributes
Database Trigger Examples (DBA and Developer)
Logging Connection Time (LOGON/LOGOFF)
Pinning Objects Upon Startup (STARTUP)
Audit Trail of Objects (CREATE/ALTER/DROP)
Disable the Ability to Drop Objects (DROP)
Disable Logins Dynamically (LOGON)
Source Version History (CREATE)
Log SQL Information Upon Shutdown (SHUTDOWN) Data Dictionary Views for Database Triggers
Re-Creating OBJECT Creation (DBMS_METADATA Package)
All examples were executed under Oracle 9.2.0.1.0.
OVERVIEWOF DATABASE TRIGGERS
In todays day and age, Oracle applications are being deployed in a variety of ways with avariety of front-end tools being used to build these applications. The constant continues to bethe Oracle database flexibility and functionality that can be realized at the database level. Since
Page 1
8/2/2019 9i Database Triggers
2/25
the introduction of the internet, many companies applications are up and running 24X7X52 andare available from anywhere by anyone. Application logic controls access to these applications,which ultimately controls access to the data. It is always important to have mechanisms in placeto ensure that access is only allowed through the application and that activity in the database ismonitored.
Prior to Oracle8i, Oracle provided the ability to build logic at the table level through databasetriggers. These triggers were great for added validation and control at the table level for DML(INSERT, UPDATE, DELETE) activity on tables. In Oracle8i, Oracle expanded this last line ofdefense from table triggers to other event triggers by introducing eight new database triggers.
These eight database triggers introduced the extension of this powerful capability to databasestartup/shutdown, server-side errors, user logons/logoffs, and object creations/alterations/drops.
The implicit execution process employed by previous database triggers is the same for thesenew triggers. Once the database trigger is created and enabled, it is executed based ondatabase actions. No explicit calls are necessary to execute these database triggers.
The catproc.sql script that is executed upon a database creation calls two main SQL scripts thatcreate the infrastructure to allow for database trigger execution. These scripts are highlighted
below and are located in the ORACLE_HOME/rdbms/admin directory:
DBMSSTDX.SQL extends the standard package by creating the DBMS_STANDARD packagethat contains a variety of functions, including the event attribute functions.
DBMSTRIG.SQL creates functions on top of the DBMS_STANDARD functions to allow for easyreference to the event attributes by granting EXECUTE on these functions and creating aPUBLIC synonym for these functions.
A segment of the DBMSTRIG.SQL file is shown below for the ORA_DICT_OBJ_NAME eventattribute.
Rem returns the object name on which the DDL statement is being done
create or replace function dictionary_obj_name return varchar2 is
beginreturn dbms_standard.dictionary_obj_name;
end;
/
grant execute on dictionary_obj_name to public
/
create or replace public synonym ora_dict_obj_name for dictionary_obj_name
/
CREATIONOF DATABASE TRIGGERS
A database trigger is created and dropped with the following commands:
CREATE OR REPLACE TRIGGER trigger_name (BEFORE|AFTER) database_trigger_event ON (DATABASEschema.SCHEMA);
DROP TRIGGER trigger_name;
When a database trigger is created, the trigger is checked for syntax, the dependency tree andprivileges are checked, and then the trigger is compiled into pcode and stored in the database.
Therefore, triggers are similar to stored packages and procedures in the sense of creation,storage, and execution of pcode. The main differences are that database triggers source code isstored in a different data dictionary table and database triggers execute implicitly based onactions, whereas, packages and procedures are explicitly called.
Page 2
8/2/2019 9i Database Triggers
3/25
If errors occur during the creation or compilation of a database trigger, then the trigger is stillcreated and enabled. If a database event executes that causes the database trigger to execute,the database event will fail. Therefore, if an error occurs during creation or compilation, thetrigger needs to be either dropped, fixed and re-created, or disabled to ensure that processingdoes not stop. To view errors, the SHOW ERRORS command can be executed or the errors canbe retrieved from the USER_ERRORS data dictionary view.
It is good practice to use the following guidelines when creating database triggers:
Keep it simple do not create complicated database triggers, follow standards, and onlycreate a database trigger when truly needed
Keep the length of the database trigger code relatively small, if it starts to get lengthy, createa stored procedure and call the procedure from the trigger; likewise if the segment of code inthe database trigger is used in other locations of code, make it modular and create a storedprocedure and call the procedure
Only create a database trigger when needed to avoid unnecessary overhead, sincedependent on the level of the database trigger, overhead will be introduced
The maximum size of a database trigger is 32K. This limitation can be increased by turning thebody of the trigger into a stored package or procedure.
SECURITYOF DATABASE TRIGGERS
In order to create a database trigger, the schema must have one of 3 Oracle system privileges:
CREATE TRIGGER: this privilege allows for a schema to create a database trigger on a table theyown.
CREATE ANY TRIGGER: this privilege allows a schema to create a database trigger on a tableowned by another schema.
ADMINISTER DATABASE TRIGGER: this privilege allows a schema to create a database widedatabase trigger.
Once a trigger is created, it is executed implicitly. Internally, Oracle fires the trigger in theexisting user transaction. However, triggers execute in the same manner as the default of storedpackages and procedures, namely, with the creator of the trigger privilege in the trigger.
Therefore, if the USER variable is referenced in a trigger, the creator of the trigger is returned,not the user that caused the trigger to fire. If any stored packages or procedures are called fromwithin a trigger, the schema creating the trigger must have EXECUTE privilege on that object.
Triggers are the same as stored packages and procedures and therefore, have dependenciesthat can cause a trigger to become invalidated. Any time a referenced stored package orprocedure is modified, the trigger becomes invalidated. If a trigger ever becomes invalidated,then Oracle will attempt to internally re-compile the trigger the next time it is referenced. As astandard, a trigger that becomes invalidated, should be recompiled manually to ensure that thetrigger will compile successfully. To compile a trigger manually, the ALTER TRIGGER command isused. This is shown below:
ALTER TRIGGER logon_trigger COMPILE;
To recompile a trigger, you must either own the trigger or have the ALTER ANY TRIGGER systemprivilege. If a package or procedure referenced in a trigger is dropped, then the trigger becomes
Page 3
8/2/2019 9i Database Triggers
4/25
invalid. When the trigger is recompiled either manually or automatically by Oracle, it will failsince it will not be able to successfully reference all of its components. In this case, the trigger ismarked with VALID WITH ERRORS and the event will fail when executed.
ENABLINGAND DISABLING DATABASE TRIGGERS
Disabled database triggers are companions to invalid objects. In some respects, a disabledtrigger is far more dangerous than an invalid object because it doesnt fail; it just doesntexecute! This can have severe consequences for applications (and, consequently, for businessprocesses) that depend on business logic stored within procedural code in database triggers. Forthis reason, you MUST run the following script regularly to ensure there are not any disabledtriggers that you are not aware of:
SELECT trigger_name, trigger_type, base_object_type,
triggering_event
FROM user_triggers
WHERE status 'ENABLED'
AND db_object_type IN ('DATABASE ', 'SCHEMA')
ORDER BY trigger_name;
TRIGGER_NAME TRIGGER_TYPE BASE_OBJECT_TYPE TRIGGERING_EVEN
------------------------ ---------------- ---------------- ---------------
DB_STARTUP_TRIGGER AFTER EVENT DATABASE STARTUP
Once the triggers are identified, they can be enabled manually or a dynamic SQL or PL/SQLscript can be created to build the SQL statements to ENABLE the triggers. To enable databasetriggers, the following three commands could be executed.
ALTER TRIGGER db_startup_trigger ENABLE; -- enabling a database trigger
ALTER TRIGGER before_insert_customer ENABLE; -- enabling a table trigger
ALTER TABLE s_customer ENABLE ALL TRIGGERS; -- enabling all triggers on a table
The preceding commands allow you to enable one trigger at a time or all the triggers on a table.To enable all triggers under a schema, the following script can be used to build an ENABLE scriptdynamically:
SET HEADING OFF
SET FEEDBACK OFF
SET PAGESIZE 0
SELECT 'ALTER TRIGGER ' || trigger_name || ' ENABLE;'
FROM user_triggers
ORDER BY table_name;
ALTER TRIGGER DB_STARTUP_TRIGGER ENABLE;
ALTER TRIGGER BEFORE_INSERT_CUSTOMER ENABLE;ALTER TRIGGER BEFORE_UPDATE_CUSTOMER ENABLE;
This script can be modified to change the word ENABLE to DISABLE and re-executed todynamically build a DISABLE script.
There may be times that you want to disable triggers for a data load or special processing. Inthis case, the enable commands shown earlier in this section could be modified as shown below:
ALTER TRIGGER DB_STARTUP_TRIGGER DISABLE;
ALTER TRIGGER before_insert_customer DISABLE;
ALTER TABLE s_customer DISABLE ALL TRIGGERS;
Page 4
8/2/2019 9i Database Triggers
5/25
Prior to version 7.3 of Oracle (version 2.3 of PL/SQL), triggers were not stored in compiledformat. This means every time the trigger was executed, the trigger was compiled and loadedinto memory. This caused additional overhead when using database triggers. Therefore, many
people kept certain functions outside of database triggers. This consideration has gone away,since the overhead is now significantly reduced with storing the compiled format.
In Oracle9i, there is an undocumented parameter _system_trig_enabled that you can set toFALSE to disable event triggers. In Oracle8i, the parameter is not hidden, and issystem_trig_enabled. This parameter can be used during an upgrade, downgrade and/or whenpatching applications.
NEW DATABASE TRIGGERS
The 20 new triggers are broken into two main categories by Oracle, namely, database systemevents and DDL/client events. For each event, there are event attributes set internally by Oraclewhen the event takes place. These event attributes can be referenced in the database triggerlogic. For example, the CREATE database trigger can reference the schema name, the type of
object created, the name of the object, etc. for the object just created.
DATABASE SYSTEM EVENTS
There are six database system event triggers. The six database system event triggers areoutlined below, along with a description and the event attributes that are set for each event.
DatabaseTrigger
BEFORE/AFTER Execution Description Attribute Event
LOGOFF BEFORE Executed when a user logs
off, at the start of the
logoff process
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
LOGON AFTER Executed when a user logs
into the database, after a
successful login of the user
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_client_ip_address
STARTUP AFTER Executed when the database is
opened; starts a separate
transaction and commits after
this trigger is complete
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
SHUTDOWN BEFORE Executed when the instance is
shutdown; prior to the
shutdown of the instance
process; not always executed
on abnormal shutdown; startsa separate transaction and
commits after this trigger is
complete
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
Page 5
8/2/2019 9i Database Triggers
6/25
SERVERERROR AFTER Executes when an Oracle error
occurs (can check for a
specific error number to only
execute for (errno=eno));
does not execute for certain
errors (1034, 1403, 1422,
1423, 4030); starts a
separate transaction and
commits after this trigger is
complete
ora_syseventora_login_userora_instance_numora_database_nameora_server_error
ora_is_servererrorspace_error_info
SUSPEND AFTER Executed whenever a server
error causes a transaction to
be suspended (example: out-
of-space error)
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_server_error
ora_is_servererror
space_error_info
The startup and shutdown triggers can only be created at the database level. The other fourdatabase system events can be created at the database or schema levels. The STARTUP triggerreturns a success, even if the trigger fails.
The SERVERERROR trigger does not execute when the following Oracle errors are returned:
ORA-01403: data not found
ORA-01422: exact fetch returns more than requested number of rows
ORA-01423: error encountered while checking for extra rows in exact fetch
ORA-01034: ORACLE not available
ORA-04030: out of process memory
For these triggers, Oracle opens an autonomous transaction scope, fires the trigger, and
commits any separate transaction.
DDL/CLIENT EVENTS
There are 14 DDL/client event triggers and these can be created at the database level and willexecute for all schemas, or these can be created at the schema level and will execute only forthe schema it is created for. When a trigger is created at the schema level, the trigger is createdin the schema specified and executes only for that schema.
This provides a great deal of flexibility depending on your environment and what you want tomonitor or respond to. The 14 DDL/client event triggers are outlined below, along with adescription and the event attributes that are set for each event.
Database
Trigger
BEFORE/AFTE
R Execution Description Attribute Events
Page 6
8/2/2019 9i Database Triggers
7/25
ALTERBEFORE/AFTER Executed when object
altered
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_type
ora_dict_obj_name
ora_dict_obj_owner
ora_des_encrypted_password
(for ALTER USER events)
ora_is_alter_column,
ora_is_drop_column (for
ALTER TABLE events)
DROP BEFORE/AFTER Executed when object is
dropped
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_type
ora_dict_obj_name
ora_dict_obj_owner
ANALYZE BEFORE/AFTER Executed when the analyze
command is executed
ora_syseventora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
ASSOCIATE
STATISTICS
BEFORE/AFTER Executed when the associate
statistics command is
executed
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
ora_dict_obj_name_listora_dict_obj_owner_list
AUDIT/NOAUDIT BEFORE/AFTER Executed when the audit or
noaudit command is executed
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
COMMENT BEFORE/AFTER Executed when the comment
command is executed
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
CREATE BEFORE/AFTER Executed when an object is
created
ora_syseventora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_type
ora_dict_obj_name
ora_dict_obj_owner
ora_is_creating_nested_table
(for CREATE TABLE events)
Page 7
8/2/2019 9i Database Triggers
8/25
DDL BEFORE/AFTER Executed when SQL DDL
commands are executed (not
executed when and
ALTER/CREATE DATABASE,
CREATE CONTROLFILE, or DDL
issued through the PL/SQL
procedure interface)
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
DISASSOCIATE
STATISTICS
BEFORE/AFTER Executed when the
disassociate statistics
command is executed
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
ora_dict_obj_name_list
ora_dict_obj_owner_list
GRANT BEFORE/AFTER Executed when the grant
command is executed
ora_sysevent
ora_login_user
ora_instance_num
ora_database_nameora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
ora_grantee
ora_with_grant_option
ora_privileges
RENAME BEFORE/AFTER Executed when the rename
command is executed
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_owner
ora_dict_obj_type
REVOKE BEFORE/AFTER Executed when the revoke
command is executed
ora_syseventora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
ora_revokee
ora_privileges
TRUNCATE BEFORE/AFTER Execute when a table is
truncated
ora_sysevent
ora_login_user
ora_instance_num
ora_database_name
ora_dict_obj_name
ora_dict_obj_type
ora_dict_obj_owner
The new triggers are ideal for DBAs to build mechanisms based on certain events. When thedatabase is started, the objects that need to be pinned can now be moved from the startup SQLscript to the STARTUP trigger. When the database is shut down, statistics scripts can beexecuted to log information into monitoring tables with the SHUTDOWN trigger. Error trappingcan be enhanced with the SERVERERROR trigger. Capturing user connect time can be handled
Page 8
8/2/2019 9i Database Triggers
9/25
through the LOGON and LOGOFF triggers. An object audit trail can be created through theCREATE, ALTER, and DROP triggers.
EVENT ATTRIBUTES
With the introduction of the 20 new database triggers, came the creation of attribute events or
variables that are set when a certain database trigger event is executed. The previous sectionhighlighted each of the database triggers, along with the event attributes that are set and canbe referenced for each trigger. Below is a list of each of the attribute events, the data type and ashort description.
Attribute Event Data Type Description
ora_client_ip_address VARCHAR2Provides the IP address of the clientmachine when using TCP/IP
ora_database_name VARCHAR2(50)Provides the database name
ora_des_encrypted_password VARCHAR2
Provides the DES encrypted password of
the user being created or altered
ora_dict_obj_name VARCHAR(30)Provides the object name of the objectbeing manipulated
ora_dict_obj_name_list(name_list OUTora_name_list_t)
BINARY_INTEGERProvides a list of object names beingmanipulated
ora_dict_obj_owner VARCHAR(30)Provides the owner of the object beingmanipulated
ora_dict_obj_owner_list(owner_list OUT ora_name_list_t)
BINARY_INTEGERProvides the owners of the objects beingmanipulated
ora_dict_obj_type VARCHAR(20) Provides the type of object beingmanipulated
ora_grantee(user_listOUT ora_name_list_t)
BINARY_INTEGER Provides the number of grantees
ora_instance_num NUMBER Provides the instance number.
ora_is_alter_column(column_name IN VARCHAR2)
BOOLEANProvides a return value of TRUE if thespecified column is altered
ora_is_creating_nested_table BOOLEANProvides a return value of TRUE if thecurrent event is creating a nested table
ora_is_drop_column(
column_name IN VARCHAR2) BOOLEAN
Provides a return value of TRUE if the
specified column is dropped
ora_is_servererror BOOLEANProvides a return value of TRUE is the errorspecified is on the error stack
ora_login_user VARCHAR2(30) Provides the login schema
ora_partition_pos BINARY_INTEGERProvides the position in a CREATE TABLEcommand where the partition clause can beinserted when using the INSTEAD OF trigger
ora_privilege_list(privilege_list OUT
BINARY_INTEGER Provides the list of privileges being granted
Page 9
8/2/2019 9i Database Triggers
10/25
ora_name_list_t) or revoked
ora_revokee (user_list OUTora_name_list_t)
BINARY_INTEGERProvides a list of the revokees of the revokecommand
ora_server_error NUMBERProvides the error on the error stack for theposition specified in the stack (1 meaningthe top of the stack)
ora_server_error_depth BINARY_INTEGERProvides the total number of errors on theerror stack
ora_server_error_msg(position in binary_integer)
VARCHAR2Provides the error on the error stack for theposition specified in the stack (1 meaningthe top of the stack)
ora_server_error_num_params(position in binary_integer)
BINARY_INTEGER
Provides the number of strings that havebeen substituted into the error message onthe error stack for the position specified in
the stack (1 meaning the top of the stack)
ora_server_error_param(position in binary_integer,param in binary_integer)
VARCHAR2
Provides the matching substitution value inthe error message for the parameternumber specified in conjunction with theposition specified on the stack ( 1 meaningthe top of the stack)
ora_sql_txt (sql_text outora_name_list_t)
BINARY_INTEGER
Provides the SQL statement of thestatement that caused the trigger toexecute (if the statement is lengthy, it willseparate it into multiple PL/SQL tableelements); the value returned specifies the
number of elements
ora_sysevent VARCHAR2(20)Provides the system or client event thatcaused the trigger to execute
ora_with_grant_option BOOLEANProvides a return value of TRUE if theprivileges are granted with the grant option
Space_error_info(error_number OUT NUMBER,error_type OUT VARCHAR2,object_owner OUT VARCHAR2,table_space_name OUTVARCHAR2,object_name OUT VARCHAR2,
sub_object_name OUTVARCHAR2)
BOOLEAN
Provides a return value of true if the error isrelated to an out-of-space error andprovides the object information of theobject with the error
These attribute events allow extreme flexibility and functionality in each of the database triggersand should be used as necessary.
DATABASE TRIGGER EXAMPLES (DBA AND DEVELOPER)
The power and flexibility is endless with the 20 new database triggers. This section provides avariety of examples to illustrate this power. A list of the examples is provided below.
Logging Connection Time (LOGON/LOGOFF)
Page 10
8/2/2019 9i Database Triggers
11/25
Pinning Objects Upon Startup (STARTUP)
Audit Trail of Objects (CREATE/ALTER/DROP)
Disable the Ability to Drop Objects (DROP)
Disable Logins Dynamically (LOGON)
Source Version History (CREATE)
Log SQL Information Upon Shutdown (SHUTDOWN)
LOGGING CONNECTION TIME (LOGON/LOGOFF)
The following example creates a logon statistics table and a LOGON and LOGOFF databasetrigger to capture the time when a user connects/disconnects to/from the database.
CREATE TABLE session_logon_statistics
(sid NUMBER,
user_logged VARCHAR2(30),
start_time DATE,end_time DATE);
CREATE OR REPLACE TRIGGER logon_log_trigger
AFTER LOGON ON DATABASE
BEGIN
INSERT INTO session_logon_statistics
(sid, user_logged, start_time)
SELECT DISTINCT sid, ora_login_user, SYSDATE
FROM v$mystat;
END;
/
CREATE OR REPLACE TRIGGER logoff_log_trigger
BEFORE LOGOFF ON DATABASEBEGIN
UPDATE session_logon_statistics
SET end_time = SYSDATE
WHERE sid = (select distinct sid from v$mystat)
AND end_time IS NULL;
END;
/
The SID is selected from the V$MYSTAT view. SELECT privilege must be granted on theV_$MYSTAT view to the creator of these triggers. The following script retrieves the informationfrom the SESSION_LOGON_STATISTICS table.
COLUMN user_logged FORMAT a15COLUMN start_time FORMAT a20
COLUMN end_time FORMAT a20
SELECT sid, user_logged,
TO_CHAR(start_time, 'MM/DD/YYYY HH24:MI:SS') start_time,
TO_CHAR(end_time, 'MM/DD/YYYY HH24:MI:SS') end_time
FROM session_logon_statistics
order by sid, user_logged, start_time;
SID USER_LOGGED START_TIME END_TIME
---------- --------------- -------------------- --------------------
12 TRIGGER_TEST 01/22/2003 19:11:53 01/22/2003 19:17:22
Page 11
8/2/2019 9i Database Triggers
12/25
12 TRIGGER_TEST 01/22/2003 19:17:24 01/22/2003 19:17:46
13 PLSQL_USER 01/22/2003 19:12:19 01/22/2003 19:18:13
13 SYS 01/22/2003 19:18:38 01/22/2003 19:19:34
13 SYS 01/22/2003 19:19:35 01/22/2003 19:19:53
13 SYS 01/22/2003 19:19:59
14 TRIGGER_TEST 01/22/2003 19:12:29 01/22/2003 19:18:03
PINNING OBJECTS UPON STARTUP (STARTUP)
The following example creates a startup mechanism that pins objects in the shared pool. Itprovides a dynamic and flexible method to control the pinning by merely inserting and deletingfrom a database table.
Because Oracle uses an LRU algorithm for the caching of objects in the Shared Pool, objects canbe flushed out of the Shared Pool. If the objects are large, this will cause degradation inperformance and possible errors because objects are loaded into the Shared Pool in contiguoussegments. Heavily executed or large and important stored PL/SQL program units should becached or pinned in the Shared Pool. Stored PL/SQL program units get pinned in the object cacheand cursors get pinned in the SQL Area.
Oracle provides a procedure in the DBMS_SHARED_POOL package to pin these objects. This isthe only method of pinning these objects in the shared pool and this package is not created bydefault. The dbmspool.sql script must be executed under the SYS schema to create this packageBy default, even in Oracle 9.2, no objects, not even the STANDARD package is pinned by default.
The following is a pinning mechanism that allows stored PL/SQL program units to be pinned orunpinned by inserting or deleting the name of the program unit from a database table.
The following command creates the table to store the names of the stored PL/SQL program unitsto pin. This should be created under a user with DBA privilege.
CREATE TABLE objects_to_pin
(owner VARCHAR2(30) NOT NULL,
object VARCHAR2(128) NOT NULL,type VARCHAR2(1) NOT NULL);
The following is a basic method of inserting objects to pin into the table. This can be modified tobe more robust and often a Forms front-end interface is created to allow for this function.
INSERT INTO objects_to_pin
(owner, object, type)
VALUES
(UPPER('&owner'), UPPER('&object'), UPPER('&type'));
The type needs to follow the same conventions as defined in the SHARED_POOL package. This is
outlined in the creation script of the DBMS_SHARED_POOL script (dbmspool.sql) and is includedfor reference below:
Value Kind of Object to keep
----- ----------------------
P package/procedure/function
Q sequence
R trigger
T type
JS java source
JC java class
Page 12
8/2/2019 9i Database Triggers
13/25
JR java resource
JD java shared data
C cursor
The following procedure takes one parameter to signify if the objects in the table should be
pinned or unpinned. The default is to pin the objects. A U as input will unpin the objects in thetable.
CREATE OR REPLACE PROCEDURE pin_objects
(p_pin_flag_txt IN VARCHAR2 := 'P') IS
-- The p_pin_flag_txt is either 'P' for pin
-- or 'U' for unpin.
CURSOR cur_pin_objects IS
SELECT owner || '.' owner,
object, type
FROM objects_to_pin
ORDER BY owner, object;
BEGIN
FOR cur_pin_objects_rec IN cur_pin_objects LOOP
IF p_pin_flag_txt = 'U' THEN
DBMS_SHARED_POOL.UNKEEP(cur_pin_objects_rec.owner ||
cur_pin_objects_rec.object, cur_pin_objects_rec.type);
ELSE
DBMS_SHARED_POOL.KEEP(cur_pin_objects_rec.owner ||
cur_pin_objects_rec.object, cur_pin_objects_rec.type);
END IF;
END LOOP;
END pin_objects;
/
The pin_objects procedure should be called from the database startup script to make certain thePL/SQL objects are pinned immediately, which will ensure the Shared Pool space is contiguously
allocated in memory. In Oracle 8.1, the pin_objects procedure can be moved from the databasestartup script to the new STARTUP database trigger.
The STANDARD package and SOURCE_HISTORY were insert into the OBJECTS_TO_PIN table usingthe INSERT script above. The following output displays the contents of this table.
COLUMN object FORMAT a30
SELECT *
FROM objects_to_pin;
OWNER OBJECT TYPE
--------------- ------------------------------ ------------
SYS STANDARD P
TRIGGER_TEST SOURCE_HISTORY R
The following query displays the stored PL/SQL program units information regarding pinning. Thescript below has been modified to focus on the two objects that we are attempting to pin. TheWHERE clause would usually only contain the following condition.
WHERE kept = 'YES'
The modified script is shown and executed below.COLUMN owner FORMAT a15
COLUMN name FORMAT a25
Page 13
8/2/2019 9i Database Triggers
14/25
COLUMN type FORMAT a12
SET PAGESIZE 58
SELECT owner, name, type, kept
FROM v$db_object_cache
WHERE name in ('STANDARD', 'SOURCE_HISTORY');
OWNER NAME TYPE KEP
--------------- ------------------------- ------------ ---
SYS STANDARD PACKAGE NO
SYS STANDARD PACKAGE BODY NO
TRIGGER_TEST SOURCE_HISTORY TABLE NO
TRIGGER_TEST SOURCE_HISTORY TRIGGER NO
The previous query can be executed to list the sharable memory (sharable_mem column)required for the object and the number of times the object was loaded and executed (loads andexecutions columns) to determine which objects should be pinned.
In order to take this example full circle, a database startup script is created that calls thePIN_OBJECTS procedure. This will ensure that objects will be pinned upon startup no matter
where the database is being started from (whether manually or through a script).
CREATE OR REPLACE TRIGGER db_startup_trigger
AFTER STARTUP ON DATABASE
BEGIN
pin_objects;
END;
/
The database is then shutdown and started up and the query against the V$DB_OBJECT_CACHEview is executed again as shown below.
SQL> shutdown
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORACLE instance started.
Total System Global Area 135338868 bytes
Fixed Size 453492 bytes
Variable Size 109051904 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
Database mounted.
Database opened.
OWNER NAME TYPE KEP
--------------- ------------------------- ------------ ---
SYS STANDARD PACKAGE YES
SYS STANDARD PACKAGE BODY YES
TRIGGER_TEST SOURCE_HISTORY TABLE NO
TRIGGER_TEST SOURCE_HISTORY TRIGGER YES
Pinning frequently executed Oracle objects and application objects is recommended, butremember adequate space must still exist in the Shared Pool for the objects that are not pinned.
Page 14
8/2/2019 9i Database Triggers
15/25
AUDIT TRAILOF OBJECTS (CREATE/ALTER/DROP)
The next example provides the ability to build your own flexible object audit trail. The examplebelow creates database triggers to capture and log every CREATE, ALTER and DROP operationon the database.
First a table is created to store the audit information.
CREATE TABLE audit_object_mods
(mod_date DATE,
type_of_mod VARCHAR2(20),
mod_user VARCHAR2(30),
instance_num NUMBER,
database_name VARCHAR2(50),
object_owner VARCHAR2(30),
object_type VARCHAR2(20),
object_name VARCHAR2(30));
Next, the CREATE, ALTER, and DROP database triggers are created. These are created for all
schemas. If the audit was only focused on one particular schema, then the ON DATABASE linewould be changed to ON TRIGGER_TEST.SCHEMA where TRIGGER _TEST is the name of theschema desired to audit.
CREATE OR REPLACE TRIGGER create_object_trigger
AFTER CREATE ON DATABASE
BEGIN
INSERT INTO audit_object_mods
(mod_date, type_of_mod, mod_user,
instance_num, database_name,
object_owner, object_type, object_name)
VALUES
(sysdate, ora_sysevent, ora_login_user,
ora_instance_num, ora_database_name,ora_dict_obj_owner, ora_dict_obj_type, ora_dict_obj_name);
END;
/
CREATE OR REPLACE TRIGGER alter_object_trigger
AFTER ALTER ON DATABASE
BEGIN
INSERT INTO audit_object_mods
(mod_date, type_of_mod, mod_user,
instance_num, database_name,
object_owner, object_type, object_name)
VALUES
(sysdate, ora_sysevent, ora_login_user,
ora_instance_num, ora_database_name,
ora_dict_obj_owner, ora_dict_obj_type, ora_dict_obj_name);
END;
/
CREATE OR REPLACE TRIGGER drop_object_trigger
AFTER DROP ON DATABASE
BEGIN
INSERT INTO audit_object_mods
(mod_date, type_of_mod, mod_user,
instance_num, database_name,
Page 15
8/2/2019 9i Database Triggers
16/25
object_owner, object_type, object_name)
VALUES
(sysdate, ora_sysevent, ora_login_user,
ora_instance_num, ora_database_name,
ora_dict_obj_owner, ora_dict_obj_type, ora_dict_obj_name);
END;
/
At this point, the audit is set up and as these operations take place in the database, they will belogged to the AUDIT_OBJECT_MODS table. To view the audit, the following script can beexecuted.
COLUMN type_of_mod FORMAT a10
COLUMN mod_user FORMAT a12
COLUMN database_name FORMAT a10
COLUMN object_owner FORMAT a12
COLUMN object_type FORMAT a10
COLUMN object_name FORMAT a25SET LINESIZE 130
SELECT mod_date, type_of_mod, mod_user, instance_num,
database_name, object_owner, object_type,
object_name
FROM audit_object_mods
ORDER BY mod_date, type_of_mod, object_owner, object_type, object_name;
MOD_DATE TYPE_OF_MO MOD_USER I_NUM DATABASE_N OBJECT_OWNER OBJECT_TYP OBJECT_NAME
--------- ---------- ------------ ----- ---------- ------------ ---------- -------------------------
27-JAN-03 CREATE TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TRIGGER ALTER_OBJECT_TRIGGER27-JAN-03 CREATE TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TRIGGER DROP_OBJECT_TRIGGER
27-JAN-03 CREATE TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST PROCEDURE PIN_OBJECTS
27-JAN-03 CREATE TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TRIGGER DB_STARTUP_TRIGGER
27-JAN-03 DROP TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TRIGGER DATABASE_STARTUP_TRIGGER27-JAN-03 CREATE TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TABLE TEST14
27-JAN-03 ALTER TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TRIGGER DB_STARTUP_TRIGGER27-JAN-03 ALTER TRIGGER_TEST 1 TUSC.WORLD TRIGGER_TEST TRIGGER DB_STARTUP_TRIGGER
The individual CREATE, ALTER, and DROP database triggers created previously can be replacedwith one trigger creation with the use of the OR condition as shown below.
CREATE OR REPLACE TRIGGER c_a_d_object_trigger
AFTER CREATE OR ALTER OR DROP ON DATABASE
BEGIN
INSERT INTO audit_object_mods
(mod_date, type_of_mod, mod_user,
instance_num, database_name,
object_owner, object_type, object_name)
VALUES(sysdate, ora_sysevent, ora_login_user,
ora_instance_num, ora_database_name,
ora_dict_obj_owner, ora_dict_obj_type, ora_dict_obj_name);
END;
/
DISABLETHE ABILITYTO DROP OBJECTS (DROP)
The following example illustrates how a trigger can be created for specific schema to disallowthe ability to DROP objects. The trigger is for the PLSQL_USER.
Page 16
8/2/2019 9i Database Triggers
17/25
CREATE OR REPLACE TRIGGER stop_drop_trigger
BEFORE DROP ON plsql_user.SCHEMA
BEGIN
RAISE_APPLICATION_ERROR (
num => -20000,
msg => 'Cannot DROP Objects');
END;
/
When the PLSQL_USER attempts to DROP any object an error will result as shown below.
SHOW USER
USER is "PLSQL_USER"
DROP TABLE temp;
drop table temp
*
ERROR at line 1:ORA-00604: error occurred at recursive SQL level 1
ORA-20000: Cannot DROP Objects
ORA-06512: at line 2
DISABLE LOGINS DYNAMICALLY (LOGON)
Oracle has added features and commands to allow a DBA to perform more and more of theirresponsibilities while the database is up and running, thus reducing the time of off-hoursadministration. With database triggers, the logon trigger allows a DBA to disable new logons bysetting a flag in a table. The following table can be used for this toggle flag.
CREATE TABLE logons_allowed
(logons_allowed VARCHAR2(3) NOT NULL);
A record is inserted into this table with the value of YES. The following logon trigger is created toreference this table upon logon and look for the value of the record to determine if logins areallowed.
CREATE OR REPLACE TRIGGER logon_allow_trigger
AFTER LOGON ON DATABASE
DECLARE
CURSOR logon_allowed IS
SELECT logons_allowed
FROM logons_allowed;
lv_allowed logons_allowed.logons_allowed%TYPE;BEGIN
OPEN logon_allowed;
FETCH logon_allowed INTO lv_allowed;
IF lv_allowed != 'YES' THEN
CLOSE logon_allowed;
RAISE_APPLICATION_ERROR (
num => -20000,
msg => 'Logins Not Allowed.');
ELSE
CLOSE logon_allowed;
END IF;
Page 17
8/2/2019 9i Database Triggers
18/25
END;
/
The trigger looks for a value of YES and if the value is NOT YES, then the login will not succeedand the login will fail with an error. To illustrate, the table is updated and the logons_allowed
value is set to NO. A user attempts to login and they get the following error:
SQL*Plus: Release 9.2.0.1.0 - Production on Wed Jan 22 21:45:27 2003
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
ERROR:
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: Logins Not Allowed.
ORA-06512: at line 12
Any time an error is returned either at runtime as forced in the above trigger or if the above
trigger was INVALID due to an error upon creation, the SYS and SYSTEM users are exempt fromerrors in the logon triggers and will be allowed to logon. Likewise, any schema with ADMINISTERDATABASE TRIGGER system privilege follows the same logic. Therefore, when the creator of thetrigger above (TRIGGER_TEST who has the above privilege), as well as the SYS and SYSTEMusers attempt to logon, they succeed. If the trigger was created with an error and is INVALID, the3 users and any schema with the privilege above would still succeed upon logon. However, if thetrigger was created with an error and is INVALID and anyone else attempts to logon, they willreceive the following message.
SQL*Plus: Release 9.2.0.1.0 - Production on Tue Jan 28 15:06:21 2003
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
ERROR:
ORA-04098: trigger 'TRIGGER_TEST.LOGON_ALLOW_TRIGGER' is invalid and failed
re-validation
Enter user-name:
SOURCE VERSION HISTORY(CREATE)
The ability to view the source code of stored PL/SQL objects in the database provides a lot ofadvantages, however, the biggest disadvantage is that developers often times bypass versioncontrol mechanisms in place to make a quick fix and forget to update the main source codeversion of the PL/SQL object that resides outside of the database. The problem comes in whenthe next change is made the correct way by modifying the code outside the database and thenrecreating it in the database. The prior change made in the database is now lost. I have heardabout this many times.
The new triggers provide a mechanism to help this problem and create an audit trail/version ofall PL/SQL source code created in the database. This is accomplished by inserting the newsource code for an object into a history table each time an object is created or recreated. It isaccomplished behind the scenes with the CREATE trigger. Each of the creations is alsotimestamped with the creation date.
A history table is first created that mirrors the DBA_SOURCE table as shown below.
Page 18
8/2/2019 9i Database Triggers
19/25
CREATE TABLE source_history
(change_date DATE NOT NULL,
owner VARCHAR2(30) NOT NULL,
name VARCHAR2(30) NOT NULL,
type VARCHAR2(20),line NUMBER NOT NULL,
text VARCHAR2(4000));
A CREATE trigger is then created that will insert into the SOURCE_HISTORY table after each newobject creation as shown below.
CREATE OR REPLACE trigger source_history
AFTER CREATE ON DATABASE
BEGIN
INSERT INTO source_history
SELECT SYSDATE, owner, name, type, line, text
FROM dba_source
WHERE owner = ORA_DICT_OBJ_OWNERAND name = ORA_DICT_OBJ_NAME
AND type = ORA_DICT_OBJ_TYPE;
END source_history;
/
The same scripts created for the DBA_SOURCE view can now be used on this view by onlychanging the view name to SOURCE_HISTORY. A sample script is shown below with the querylimited to one object.
COLUMN owner FORMAT a12
COLUMN name FORMAT a11
COLUMN line FORMAT 9999
COLUMN text FORMAT a60 WORD_WRAPPEDSELECT change_date, owner, name, type, line, text
FROM source_history
WHERE name = 'PIN_OBJECTS'
order by change_date, owner, name, type, line;
CHANGE_DA OWNER NAME TYPE LINE TEXT
--------- ------------ ----------- ---------- ----- ------------------------------------------------------------
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 1 PROCEDURE pin_objects27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 2 (p_pin_flag_txt IN VARCHAR2 := 'P') IS
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 3 -- The p_pin_flag_txt is either 'P' for pin
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 4 -- or 'U' for unpin.
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 5 CURSOR cur_pin_objects IS27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 6 SELECT owner || '.' owner,
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 7 object
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 8 FROM objects_to_pin
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 9 ORDER BY owner, object;27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 10 BEGIN
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 11 FOR cur_pin_objects_rec IN cur_pin_objects LOOP
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 12 IF p_pin_flag_txt = 'U' THEN
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 13 DBMS_SHARED_POOL.UNKEEP(cur_pin_objects_rec.owner ||27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 14 cur_pin_objects_rec.object, 'P');
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 15 ELSE27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 16 DBMS_SHARED_POOL.KEEP(cur_pin_objects_rec.owner ||
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 17 cur_pin_objects_rec.object, 'P');27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 18 END IF;
27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 19 END LOOP;27-JAN-03 TRIGGER_TEST PIN_OBJECTS PROCEDURE 20 END pin_objects;
This query can also be changed to include the time .
Page 19
8/2/2019 9i Database Triggers
20/25
LOG SQL INFORMATION UPON SHUTDOWN (SHUTDOWN)
The following illustrates a method of logging information when the database is shutdown. Thiscan be extended to log more information or perform certain operations. The example logsinformation from the V$SQLAREA view. First, a log table is created with a timestamp column as
shown below.
CREATE TABLE sqlarea_history
(log_date DATE,
disk_reads NUMBER,
executions NUMBER,
execution_ratio NUMBER,
sql_text VARCHAR2(1000));
A procedure is created to log the desired information from the view into the log table. There is alow threshold in the example below for the number of READS. This can be modified for yoursystem to only log the SQL for statements over a large number of disk reads.
CREATE OR REPLACE PROCEDURE SQLAREA_LOG AS
CURSOR c1 IS
SELECT disk_reads reads, executions exe,
ROUND(disk_reads/DECODE(executions, 0, 1, executions)) ratio,
sql_text text
FROM v$sqlarea
WHERE disk_reads > 100
ORDER BY disk_reads/DECODE(executions, 0, 1, executions) DESC;
lv_current_date DATE := SYSDATE;
BEGIN
FOR c1_rec in c1 LOOP
INSERT INTO sqlarea_history
(log_date, disk_reads, executions, execution_ratio, sql_text)
VALUES(lv_current_date, c1_rec.reads, c1_rec.exe, c1_rec.ratio,
c1_rec.text);
END LOOP;
END;
/
Lastly, the database shutdown trigger is created to call the SQLAREA_LOG procedure.
CREATE OR REPLACE TRIGGER db_shutdown_trigger
BEFORE SHUTDOWN ON DATABASE
BEGIN
sqlarea_log;
END;
/
The SQL can then be queried at anytime in the future with the following statement.
COLUMN sql_text FORMAT a25
COLUMN log_date FORMAT a19
SET PAGESIZE 58
SELECT TO_CHAR(log_date, 'MM/DD/YYYY:HH24:MI:SS') log_date,
disk_reads, executions exe, execution_ratio ratio, sql_text
FROM sqlarea_history;
Page 20
8/2/2019 9i Database Triggers
21/25
LOG_DATE DISK_READS EXE RATIO SQL_TEXT
------------------- ---------- ---------- ---------- -------------------------
01/22/2003:22:55:09 379 1 379 select o.owner#,o.obj#,de
code(o.linkname,null, dec
ode(u.name,null,'SYS',u.name),o.remoteowner), o.na
me,o.linkname,o.namespace
,o.subname from user$ u,
obj$ o where u.user#(+)=o
.owner# and o.type#=:1 an
d not exists (select p_ob
j# from dependency$ where
p_obj# = o.obj#) for upd
ate
01/22/2003:22:55:09 213 1 213 select distinct i.obj# fr
om sys.idl_ub1$ i where i
.obj#>=:1 and i.obj# not
in (select d.p_obj# from
sys.dependency$ d)
01/22/2003:22:55:09 115 1 115 select distinct d.p_obj#,
d.p_timestamp from sys.de
pendency$ d, obj$ o where
d.p_obj#>=:1 and d.d_obj
#=o.obj# and o.status!=5
DATA DICTIONARYVIEWSFOR DATABASE TRIGGERS
There are several data dictionary views that reveal information about triggers. The main twoviews center on the source code view that contains the source code for package, procedures andfunctions, but also stores the compilation status of triggers. This is important to determine if atrigger has been compiled successfully. The source code for triggers and the importantinformation regarding being ENABLED or DISABLED is also stored in the trigger views. There are3 views for each that center on the scope of the information. These are listed below.
user_triggers user_sourceall_triggers all_sourcedba_triggers dba_source
Some examples follow to exemplify the usefulness of these views. The first example scriptprovides information on the compilation status of triggers. A status of VALID indicates the triggeris compiled and is ready for execution. A status of INVALID means that the trigger needs to becompiled prior to execution. This will be automatically attempted by Oracle the next time thetrigger is fired or manually with the ALTERCOMPILE command prior to the next firing of thetrigger. I always recommend recompiling manually to ensure the compilation will be valid and if
Page 21
8/2/2019 9i Database Triggers
22/25
not, then changes can be made until it does become VALID. You always want to know prior toproduction if there will be compilation issues that you need to address.
COLUMN object_name FORMAT a24
SELECT object_name, object_type, status
FROM user_objects
WHERE object_type = 'TRIGGER';
OBJECT_NAME OBJECT_TYP STATUS
------------------------ ---------- -------
ALTER_OBJECT_TRIGGER TRIGGER VALID
CREATE_OBJECT_TRIGGER TRIGGER VALID
DB_SHUTDOWN_TRIGGER TRIGGER VALID
DB_STARTUP_TRIGGER TRIGGER VALID
DROP_OBJECT_TRIGGER TRIGGER VALID
LOGOFF_LOG_TRIGGER TRIGGER VALID
LOGON_ALLOW_TRIGGER TRIGGER VALID
LOGON_LOG_TRIGGER TRIGGER VALID
SOURCE_HISTORY TRIGGER VALIDSTOP_DROP_TRIGGER TRIGGER VALID
TEST TRIGGER VALID
TEST_LOGON TRIGGER VALID
As evidenced in the output, all triggers are VALID at the current time. If an object that isreferenced by one of these triggers is dropped or altered in any manner, this will cause thetrigger to become INVALID.
The second example provides information about the triggers in the system. This is useful tounderstand the database and schema triggers that are defined in a database.
COLUMN trigger_name FORMAT a24
COLUMN triggering_event FORMAT a15SELECT trigger_name, trigger_type, base_object_type, triggering_event, status
FROM user_triggers
WHERE db_object_type IN ('DATABASE ', 'SCHEMA');
TRIGGER_NAME TRIGGER_TYPE BASE_OBJECT_TYPE TRIGGERING_EVEN STATUS
------------------------ ---------------- ---------------- --------------- --------
ALTER_OBJECT_TRIGGER AFTER EVENT DATABASE ALTER ENABLED
CREATE_OBJECT_TRIGGER AFTER EVENT DATABASE CREATE ENABLED
DB_SHUTDOWN_TRIGGER BEFORE EVENT DATABASE SHUTDOWN ENABLED
DB_STARTUP_TRIGGER AFTER EVENT DATABASE STARTUP ENABLED
DROP_OBJECT_TRIGGER AFTER EVENT DATABASE DROP ENABLED
LOGOFF_LOG_TRIGGER BEFORE EVENT DATABASE LOGOFF ENABLED
LOGON_ALLOW_TRIGGER AFTER EVENT DATABASE LOGON ENABLED
LOGON_LOG_TRIGGER AFTER EVENT DATABASE LOGON ENABLEDSOURCE_HISTORY AFTER EVENT DATABASE CREATE ENABLED
TEST_LOGON AFTER EVENT DATABASE LOGON ENABLED
STOP_DROP_TRIGGER BEFORE EVENT SCHEMA DROP ENABLED
TEST AFTER EVENT SCHEMA LOGON ENABLED
The output identifies the triggers with the type of triggers, events that cause each to execute,the timing of the execution (when) and the execution status. Refer to the previous section onENABLING and DISABLING triggers for more information on this view.
Page 22
8/2/2019 9i Database Triggers
23/25
The last example provides the source code of each of the triggers (limited to theDB_STARTUP_TRIGGER trigger).
COLUMN trigger_name FORMAT a24
COLUMN triggering_event FORMAT a15
COLUMN trigger_body FORMAT a25 word_wrappedSELECT trigger_name, trigger_type, base_object_type, triggering_event, trigger_body
FROM user_triggers
WHERE trigger_name = 'DB_STARTUP_TRIGGER';
TRIGGER_NAME TRIGGER_TYPE BASE_OBJECT_TYPE TRIGGERING_EVEN TRIGGER_BODY
------------------ ------------ ---------------- ---------------
-------------------------
DB_STARTUP_TRIGGER AFTER EVENT DATABASE STARTUP BEGIN
pin_objects;
END;
The output provides attributes on the triggers, as well as, the entire contents of the trigger that
was created.RE-CREATING OBJECT CREATION (DBMS_METADATA PACKAGE)
In Oracle9i, there is a new package called DBMS_METADATA that provides an API to the objectcreation layer. This package provides a variety of procedures and functions (19 total) to allowmanipulation of this information. We will concentrate on the GET_DDL function that allows theobject creation statements to be retrieved. The following is the DESCRIBE of this function.
DESCRIBE dbms_metadata (output only shows the get_ddl function)
FUNCTION GET_DDL RETURNS CLOBArgument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------OBJECT_TYPE VARCHAR2 INNAME VARCHAR2 INSCHEMA VARCHAR2 IN DEFAULTVERSION VARCHAR2 IN DEFAULTMODEL VARCHAR2 IN DEFAULTTRANSFORM VARCHAR2 IN DEFAULT
The creation statements of the procedures and triggers created in this paper can be retrievedvia the DBMS_METADATA.GET_DDL function in the following code segment. The output isdisplayed to the screen, but could be directed to a flat file via the UTL_FILE package.
SET LONG 1000SELECT name, type, DBMS_METADATA.GET_DDL(type, name)
FROM user_source
WHERE line = 1;
NAME TYPE DBMS_METADATA.GET_DDL(TYPE,NAME)------------------------------ ------------ --------------------------------------------------------
DB_SHUTDOWN_TRIGGER TRIGGER CREATE OR REPLACE TRIGGER "TRIGGER_TEST"."DB_SHUTDOWN_TRIGGER"
BEFORE SHUTDOWN ON DATABASE
BEGINsqlarea_log;
END;
ALTER TRIGGER "TRIGGER_TEST"."DB_SHUTDOWN_TRIGGER" ENABLE
Page 23
8/2/2019 9i Database Triggers
24/25
DB_STARTUP_TRIGGER TRIGGER CREATE OR REPLACE TRIGGER "TRIGGER_TEST"."DB_STARTUP_TRIGGER"
AFTER STARTUP ON DATABASE
BEGIN
pin_objects;END;
ALTER TRIGGER "TRIGGER_TEST"."DB_STARTUP_TRIGGER" ENABLE
LOGOFF_LOG_TRIGGER TRIGGER CREATE OR REPLACE TRIGGER "TRIGGER_TEST"."LOGOFF_LOG_TRIGGER"BEFORE LOGOFF ON DATABASE
BEGIN
UPDATE session_logon_statistics
SET end_time = SYSDATEWHERE sid = (select distinct sid from v$mystat)
AND end_time IS NULL;
END;
ALTER TRIGGER "TRIGGER_TEST"."LOGOFF_LOG_TRIGGER" ENABLE
LOGON_LOG_TRIGGER TRIGGER CREATE OR REPLACE TRIGGER "TRIGGER_TEST"."LOGON_LOG_TRIGGER"
AFTER LOGON ON DATABASEBEGIN
INSERT INTO session_logon_statistics
(sid, user_logged, start_time)
SELECT DISTINCT sid, USER, SYSDATEFROM v$mystat;
END;
ALTER TRIGGER "TRIGGER_TEST"."LOGON_LOG_TRIGGER" ENABLE
PIN_OBJECTS PROCEDURE CREATE OR REPLACE PROCEDURE "TRIGGER_TEST"."PIN_OBJECTS"
(p_pin_flag_txt IN VARCHAR2 := 'P') IS
-- The p_pin_flag_txt is either 'P' for pin-- or 'U' for unpin.
CURSOR cur_pin_objects IS
SELECT owner || '.' owner,
object, typeFROM objects_to_pin
ORDER BY owner, object;BEGIN
FOR cur_pin_objects_rec IN cur_pin_objects LOOPIF p_pin_flag_txt = 'U' THEN
DBMS_SHARED_POOL.UNKEEP(cur_pin_objects_rec.owner ||cur_pin_objects_rec.object, cur_pin_objects_rec.type);
ELSEDBMS_SHARED_POOL.KEEP(cur_pin_objects_rec.owner ||
cur_pin_objects_rec.object, cur_pin_objects_rec.type);END IF;
END LOOP;END pin_objects;
SOURCE_HISTORY TRIGGER CREATE OR REPLACE TRIGGER "TRIGGER_TEST"."SOURCE_HISTORY"
AFTER CREATE ON DATABASEBEGIN
INSERT INTO source_historySELECT sysdate, owner, name, type, line, text
FROM dba_sourceWHERE owner = ora_dict_obj_owner
AND name = ora_dict_obj_name
AND type = ora_dict_obj_type;END;
ALTER TRIGGER "TRIGGER_TEST"."SOURCE_HISTORY" ENABLE
As can be seen in the output, the triggers are created and enabled. Only a subset of the outputis shown above, and only a basic example of the use of the DBMS_METADATA package wasshown above. This package is extremely powerful.
Page 24
8/2/2019 9i Database Triggers
25/25
SUMMARY
This paper outlined the new database triggers that were introduced in Oracle8i and enhancedeach version to increase the power and flexibility of this database feature. The new triggers wereoutlined with examples to highlight the EXTREME flexibility and functionality available.
ABOUTTHE AUTHOR
Joe Trezzo (trezzoj@tusc.com) is a cofounder, President and Chief Operating Officer of TUSC(www.tusc.com). He has been working with Oracle since version 4 and is the author of theOracle Press book titled Oracle PL/SQL Tips and Techniques. He is a regular presenter at manyOracle user groups and is in the Entrepreneur Hall of Fame.
REFERENCES
Oracle PL/SQL Tips and Techniques (Oracle Press), Joseph C. Trezzo
Oracle9i Instant PL/SQL Scripts (Oracle Press), Kevin Loney
Oracle9i DBA Handbook (Oracle Press), Kevin Loney
Oracle9i The Complete Reference (Oracle Press), Kevin Loney Oracle9i New Features (Oracle Press), Robert Freeman
PL/SQL User's Guide and Reference(Release 9.0.1 & 9.2.0), Oracle Corporation
Supplied PL/SQL Packages and Types Reference (Release 9.0.1 & 9.2.0), Oracle Corporation
Oracle9i Database Administrators Guide (Release 9.0.1 & 9.2.0), Oracle Corporation
Oracle9i SQL Reference (Release 9.0.1 & 9.2.0), Oracle Corporation
Oracle9i Database Concepts (Release 9.0.1 & 9.2.0), Oracle Corporation
Oracle9i Application Developers Guide - Fundamentals (Release 9.0.1 & 9.2.0), OracleCorporation
Oracle9i Database New Features (Release 9.0.1 & 9.2.0), Oracle Corporation $ORACLE_HOME/rdbms/doc/README_rdbms.htm
www.tusc.com
www.osborne.com
Neither TUSC nor the author guarantees this document to be error-free. Please providecomments/questions to trezzoj@tusc.com.
http://www.tusc.com/http://www.osborne.com/mailto:trezzoj@tusc.comhttp://www.tusc.com/http://www.osborne.com/mailto:trezzoj@tusc.com