Вы находитесь на странице: 1из 42

Procedures, Packages, Functions, and Triggers

19
C H A P T E R

In This Chapter
Discovering knowledge at hand for the journey ahead Finding where this chapter fits in with your enterprise Using a simple library system as a case study Deciding when and how to use stored Procedures and functions Using Packages for business Object modeling Comprehending stored subprogram internals Using Triggers Handling errors proactively

nowing how to use stored subprograms is paramount in distributing business processes in any enterprise using Oracle8. This chapter will assist you in the evolution of implementing solutions using stored Procedures, functions, Packages, and Triggers.

Knowledge at Hand for the Journey Ahead


This chapter enhances the knowledge gained from the previous chapter on PL/SQL. From the last chapter, you will immediately want to know how to save and reuse the created PL/SQL and also make it available for others to execute. This chapter explains to use stored Procedures, functions, and Packages. Through the use of Triggers, you also learn how to execute PL/SQL and SQL before or after data is inserted, updated, or deleted from a Table. The preceding PL/SQL blocks are defined as anonymous blocks. An anonymous block is a PL/SQL block that has no name and is not resident in the Oracle Data Dictionary. They

462

Chapter 19 3 Procedures, Packages, Functions, and Triggers

are termed anonymous because they can only be executed when they are compiled and loaded into memory prior to a call from an application. Stored Procedures, functions, Packages, and Triggers within the Oracle world are also known as subprograms. You can express business- or database-related tasks through the use of logically grouped SQL and PL/SQL statements within these subprograms. You can also create subprograms strictly for local execution in tools that have the PL/SQL engine. For example, Oracle Forms and SQL*Plus can alternately be stored in the Oracle Data Dictionary, where they are available to other Users and applications connected to the Oracle database. Such subprograms are known as stored subprograms. The only difference between subprograms and stored subprograms is the latter requires a CREATE command to allow database residency. This chapter focuses on stored subprograms. Stored subprograms are stored in a Users Schema in a compiled database format known as pseudocode (p-code). In this method, when called, Oracle loads the Object into a shared pool in the System Global Area (SGA). Then the PL/SQL engine and SQL executors collaborate to process the statements within that Object. The following diagram, Figure 19-1, conceptually illustrates how a stored subprogram is executed from a client application.

Your Enterprise System and Stored Subprograms


In todays world of distributed processing and brokering requests for work over an enterprise, stored Procedures, functions, and Packages can be treated as Objects that abstract data-related tasks from a client application and migrate it to the database. While residing in the database, it can execute extremely quickly in a compiled format. I discuss the many reasons why you should integrate such Objects into an enterprise-wide solution later in this chapter. Business Object design is becoming the norm in todays development of mission critical applications. Objects are required to be: 3 Extensible 3 Modular 3 Reusable 3 Maintainable 3 Abstracted

Chapter 19 3 Your Enterprise System and Stored Subprograms

463

Oracle server
PL/SQL engine

System global area


Function B If emp_num>100 Then Execute Function A End If Function call

Program code

Program code

u BEGIN ed oc --------------------Pr ----------------------------------------IF -----------THEN -------------------ELSE -------------------END IF --------------------------------------------------------------------------------END

ra

ta ls

tem

t en Procedural statement executor

SQL statement executor

Application interfacing the Oracle8 server Function B

Procedure B

Function B

Trigger C Package A

Figure 19-1: This is a sample of a stored subprogram execution.

Oracle stored subprograms provide the capability to embrace all the preceding business Object requirements for the following reasons: 3 You can use the powerful PL/SQL language to custom-tailor your business needs. 3 Stored subprograms are Objects in their own right. Thus, you can break programs down into manageable well-defined logical modules that translate to Oracle stored subprograms. This process supports top-down design and the stepwise refinement approach to problem solving.

SQL

464

Chapter 19 3 Procedures, Packages, Functions, and Triggers

3 Once created and tested, stored subprograms can be used with confidence. You can usually make modifications to well-designed loosely coupled subprograms without affecting the rest of the component architecture. 3 To use stored subprograms, you must know what they do, not how they work. Therefore, you can design business applications without worrying about specific implementation details. The easiest way to understand stored Procedures and functions is to perceive them as their counterpart Procedures and functions in C, PowerBuilder, Delphi, or any other third- or fourth-generation language. Procedures and functions enable you to combine the ease and flexibility of SQL with the procedural functionality of a structured programming language through the use of PL/SQL. The major difference between an Oracle stored Procedure and an Oracle function is a function has to return a value. Packages, on the other hand, can be best understood as logically grouped Procedures and functions encapsulated together in a single unit. Here each exposed Procedure or function within a Package can be called independently. One important aspect of Oracle Procedures and functions residing in Packages is you can overload them.

Chapter Case Study


To catalyze your understanding and comprehension of this chapter, I use a simple library scenario. The Table descriptions follow:
Students Books Books_Loaned Department Books_Reserved Students_Fines

Contains a list of all student and respective information. Contains a list of library books. Contains a list of books on loan to students. Contains a list of departments in which students may reside. Contains a list of books reserved by students. Contains a list of students that have book fines.

Library system workflow


A student may go to the library and either request any book in the system or request a list of books recommended by a particular department. If the books are available, the student can borrow them for a three-week loan period. The student can renew the books during the loan period if the books are not reserved while on loan. If the student returns the books after the loan period, the student accumulates daily charges on the books due.

Chapter 19 3 Stored Procedures

465

Stored Procedures
Stored Procedures can be instrumental in distributing business and data processing from your client application to the database server. The database server will almost certainly be a fault tolerant machine and possess more CPU power than the client machines. It possesses the capability to process most business tasks extremely quickly and securely. At the same time, it can reduce the network traffic between the client and the Oracle server. It makes good sense to use stored Procedures in most database-intensive applications. In most application development environments, which contain system architects, developers, and database administrators, the developers have to implement the application in their base programming language (PowerBuilder, C++, Delphi, or Visual Basic). Situations arise where embedded SQL over stored Procedures is used to implement a business- or data-related task. Such preferences result from the basic principles of not knowing how to construct a stored Procedure. Creating stored Procedures is not rocket science, but there is some effort required to understand them.This section focuses on the methodical process of creating, altering, and maintaining stored Procedures. To distribute your applications truly and efficiently, it is important to understand these concepts as combined with the power of PL/SQL and SQL.

Creating stored Procedures by example


Stored Procedures follow a simple syntactical Schema definition. Even the more complex forms of stored Procedures can be observed to bind to this simple creation structure. The typical structure of a stored Procedure follows:
CREATE Procedure <Procedure_name> <argument_list> Variable Declaration Section BEGIN PL/SQL or SQL Execution section EXCEPTION PL/SQL or SQL Execution section END;

Case study: stored Procedure example


Now lets look at a simple stored Procedure that enables a student to borrow a book. The stored Procedure receives a student id_ to identify the student and a book_id to identify the book requested for loan. The stored Procedure then returns a status of the book loan operation back to the caller.
CREATE OR REPLACE PROCEDURE loan_book(student_num IN INTEGER, book_num IN INTEGER, loan_status IN OUT VARCHAR2 ) AS

466

Chapter 19 3 Procedures, Packages, Functions, and Triggers

loan_key INTEGER; reserve_key INTEGER; book_due DATE; book_wait INTEGER; reserved_loaned EXCEPTION; BEGIN /*Check if the book is on loan or reserved */ reserve_key := book_reserved(book_num); SELECT book_loan_id INTO loan_key FROM BOOKS WHERE book_id = book_num; IF loan_key > 0 OR reserve_key > 0 THEN IF loan_key > 0 THEN -- Get the due back date of the book SELECT bl_loan_date INTO book_due FROM BOOKS_LOANED WHERE bl_loan_id = loan_key; END IF; IF reserve_key > 0 THEN -- Get the wait list on the book SELECT reserved_wait_no INTO book_wait FROM BOOKS_RESERVED WHERE reserved_id = reserve_key; END IF; RAISE reserved_loaned; ELSE -- Book is available to be loaned INSERT INTO BOOKS_LOANED VALUES ( books_on_loan.nextval, book_num, student_num, SYSDATE, 0); COMMIT; UPDATE BOOKS SET book_loan_id = books_on_loan.currval WHERE book_id = book_num; COMMIT; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN loan_status := The book could not be found in the Library System.; WHEN reserved_loaned THEN IF loan_key > 0 THEN loan_status := The book is currently on loan and is due for return on || (book_due + 30) || .; END IF; IF reserve_key > 0 THEN Loan_status := loan_status || || The book is reserved with a waiting list of || book_wait || persons ; END IF; END;

Chapter 19 3 Stored Procedures

467

Immediately the similarities will be obvious. The preceding example contains the CREATE command with parameter definitions, a variable declaration section, a Procedure body of PL/SQL and SQL expressions, and, importantly, an exceptionhanding section.

Create Procedure syntax


As with all database Objects, you must create stored Procedures using the CREATE command. The following syntax creates a stored Procedure:
CREATE [OR REPLACE] PROCEDURE Procedure_name [(argument [{IN | OUT | IN OUT}] Datatype [{:= | DEFAULT} expression],, [(argument [{IN | OUT | IN OUT}] Datatype)] {IS | AS} Procedure Body
Note

You can use SQL*Plus or the Oracle SQL Worksheet tools to create stored Procedures.

Stored Procedure components


A stored Procedure is comprised of two parts: the specification and the body. The specification of the stored Procedure defines the stored Procedure name and the formal parameters required to execute it. The body of the stored Procedure defines where any business- or data-related tasks have to be coded through PL/SQL and SQL expressions.

Specification section
CREATE [OR REPLACE] <Procedure_name>

The CREATE keyword used alone with a legal PL/SQL stored Procedure name initiates the creation of a stored Procedure. The Procedure name given to a stored Procedure uniquely identifies it within a single Schema. Any modifications to the Procedure after successful creation require you to drop the stored Procedure using the DROP PROCEDURE command each time. This type of creation is typical in production environments to avoid accidental modifications to stored Procedures, but can be extremely frustrating in development environments where modifications are quite common. To alleviate this frustration, use the CREATE OR REPLACE statement. With this statement, the stored Procedure is automatically dropped (if it already exists) and re-created.
Note

The CREATE OR REPLACE method of creating stored Procedures does not prompt you to drop the Procedure first.
[(argument [{IN | OUT | IN OUT}] Datatype

468

Chapter 19 3 Procedures, Packages, Functions, and Triggers

This component of the stored Procedure statement defines the arguments that can be passed in and out of the stored Procedure during execution. This argument list is optional, in which case the stored Procedure will return a success or failure return code.

Parameters types
In Oracle, two types of parameters are used within PL/SQL: formal and actual. Both stored Procedures and functions allow formal parameters to be defined within their respective specification sections. Actual parameters are arguments from a subprogram block, which feed the stored Procedure. In constrast, formal parameters are part of the stored Procedure declaration. For example, call the loan_book Procedure from the following anonymous block:
SET SERVEROUTPUT ON --Allow output to go to your screen / DECLARE msg VARCHAR2(200); student_id INTEGER := 1; book_id INTEGER := 1; BEGIN loan_book(student_id,book_id,msg); END;

The student_id, book_id, and msg variables are actual parameters as they feed their values into the preceding Procedure. Their presence only has meaning in the context of the subprogram block. Formal parameters are the container variables used exclusively within the stored Procedure to pass back their values to their respective actual parameters in the subprogram.
Note

You cannot impose the NOT NULL Constraint on a formal parameter. Also, use different names for actual and formal parameters, even if it involves adding a prefix to their names to differentiate them.

Parameters modes
Formal parameters have modes, which describe their behavior in the definition of a stored Procedure or a function. These modes are IN, OUT and IN OUT. 3 IN defines the formal parameter as an input variable to the stored subprogram. This type of formal parameter is read-only and cannot be assigned a value within the subprogram body. The actual parameter can be a Constant (for example, 135, Tony, or a variable). 3 OUT defines the formal parameter used as a container for returning a value to its respective actual parameter. You cannot use this type of parameter within expressions as they can only be assigned values within the subprogram body. This parameter must be a variable.

Chapter 19 3 Stored Procedures

469

3 IN OUT defines the formal parameter as a container variable you can use both within expressions and assign values to return back to its respective actual parameter. This type of parameter must be a variable. The following loan_book Procedure provides an example:
CREATE OR REPLACE PROCEDURE loan_book( student_num IN INTEGER, book_num IN INTEGER, loan_status IN OUT VARCHAR2 )

The formal parameters student_num and book_num can be constants or variables. In either case, you cannot assign a value to them. You can use the formal parameter loan_status within expressions and assign it values.

Parameter datatypes
The datatype defines the legal PL/SQL datatype of a formal parameter. The difference between defining datatypes for actual and formal parameters is the formal datatypes cannot be constrained (for example, Varchar2(10) or Number(4)). Instead, you must use nonconstraining datatypes (for example, Varchar2 and Number). If there is a requirement to constrain the formal parameter, you can use %Type or %Rowtype attributes.The %Type attribute typecasts a formal parameter to a Column defined in a Table. For example, the student_id formal parameter in the loan_book Procedure could be typecast as the student_id Column in the Students Table.
student_num IN students.student_id%TYPE

Because of this attributes flexibility, an alteration of the underlying Columns does not necessitate a change of the formal parameters. The %RowType attribute creates a record that contains all the Columns in a specified Table. This attribute is mainly used to typecast OUT formal parameters where the values of a complete Table record are required. Lets assume the full details of a particular book in the library are required. Instead of declaring all the Columns of the BOOKS Table as formal parameters, you only need to specify the book%RowType formal parameter. The following example illustrates this strategy:
CREATE OR REPLACE PROCEDURE get_book_details (book_num IN books.book_id%TYPE, book_rec OUT books%ROWTYPE) ASBEGINSELECT BOOK_ID, BOOK_PUBLISHER, BOOK_AUTHOR_FIRST ,BOOK_AUTHOR_LAST,BOOK_TITLE, BOOK_SUBJECT ,BOOK_DEPT_ID

470

Chapter 19 3 Procedures, Packages, Functions, and Triggers

,BOOK_LOAN_ID book_num;END;

INTO book_rec FROM BOOKS

WHERE BOOK_ID =

To retrieve and display the book details, use the following subprogram:DECLARE BOOK_ROW BOOKS%ROWTYPE;BEGINGET_BOOK_DETAILS(1, BOOK_ROW); DBMS_OUTPUT.PUT(book_row.BOOK_ID || );DBMS_OUTPUT.PUT(book_row.BOOK_AUTHOR_FIRST || ); DBMS_OUTPUT.PUT(book_row.BOOK_AUTHOR_LAST || ); DBMS_OUTPUT.PUT(book_row.BOOK_TITLE || ); DBMS_OUTPUT.PUT(book_row.BOOK_SUBJECT || ); DBMS_OUTPUT.PUT(book_row.BOOK_DEPT_ID || ); DBMS_OUTPUT.PUT(book_row.BOOK_LOAN_ID || ); DBMS_OUTPUT.NEW_LINE; END;
Note

Important: the underlying Tables and Columns should exist before using these attributes. Also, the SELECT INTO statement must exactly match the Columns in the Table.
DEFAULT parameters

If there is a requirement to allow IN formal parameters to be initialized to a value, defaults can be implemented by the following conventions: 1. Specifying the keyword DEFAULT in the formal parameter definition:
e.g. student_num IN Students.student_id%TYPE DEFAULT 134;

2. Using an assignment statement:


student_num IN Students.student_id%TYPE := 100;
Note

You cannot dynamically bind default values to their formal parameters upon execution. For example:
student_id IN Students.student_id%TYPE DEFAULT :student_id;

Defaults allowing a subprogram to be called without specifying their DEFAULT IN actual values as the defaults will automatically be used within the subprogram. The only Constraint in using defaults is the actual parameter list in executing the subprogram must be positional or notationally correct.

Positional and named notation methods of passing parameters


You can pass arguments to the formal parameters of a subprogram by using positional or named notations. Positional notation. In the positional method of passing variables the most common method the actual parameter values directly relate to their counterpart formal parameters. The following example calls the stored Procedure loan_book:
loan_book(student_id,book_id,msg);

Chapter 19 3 Stored Procedures

471

The actual parameters are passed in the same order as their counterpart formal parameters are defined. Named Notation. The named method of passing actual parameters involves specifying the formal parameter and the actual value assigned to it. These specifications enable you to pass parameters in any order to the Procedure. The following loan_book Procedure could be called with the following syntax:
loan_book(loan_status=>msg,book_num=>book_id,student_num=> student_id);

The Procedure body


The Procedure body is analogous to an anonymous PL/SQL block, where business- and data-related tasks are defined using PL/SQL and SQL expressions. The exception to this analogy is the keyword DECLARE, which is not used to declare variables; instead, variables are defined using just the variable name and datatype. For example, the following book_loan Procedure has the following variable declarations within the Procedure body:
loan_key INTEGER; reserve_key INTEGER; book_due DATE; book_wait INTEGER; reserved_loaned EXCEPTION;

The Procedure body usually contains an error handling section called the EXCEPTION. This section is executed whenever an error is raised or occurs based on a predefined PL/SQL error group. Declared exceptions either trap execution error or constrain business conditions and execute the appropriately defined error handling code. This chapter details exceptions in a following section.

Maintaining stored Procedures


You can drop a stored Procedure by using the DROP PROCEDURE command; re-create a stored Procedure by using the CREATE PROCEDURE command. The CREATE AND REPLACE command automatically drops and re-creates the stored Procedure. Remember, the command completes the operation without a warning or prompt.

Performance issues on stored Procedures


The following list describes reasons why using stored Procedure can be beneficial in distributing data-intensive tasks to the Oracle 8 server.

472

Chapter 19 3 Procedures, Packages, Functions, and Triggers

Reduction in network traffic


The type and quantity of piped information on an organizations network can greatly affect network performance. Because stored Procedures only require the calling parameters, they prevent the transmission of complete SQL statements across the network. Also, the complex content of a stored Procedure is executed locally on the Oracle server, thereby preventing possible multiple SQL execution commands from traveling across a network.

Compiled state
Stored Procedures are executed in a compiled format, which greatly reduces code execution times.

Memory residence
Upon execution, stored Procedures reside in an Oracle shared memory pool. This strategy reduces disk I/O compared to loading it on every call. Only a single copy of a stored Procedure is required in memory.

Integrity and maintenance


Stored Procedures can provide a single point of development, testing, and deployment of business tasks. Once tested and placed in production, you can reuse and maintain the stored Procedure from one central location.

Functions
Functions are similar to stored Procedures except they are required to return a value. Here is an easy way to differentiate between stored Procedures and functions: stored Procedures perform an action while functions compute a value. Using functions in the same manner as a stored Procedure is a poor standard and a semantic issue for developing a system. For example, the loan_book Procedure could easily be defined as a function. With Table updating and insertion occurring, however, this Procedure is not a logical candidate for an Oracle function.

Creating functions by example


The syntax for creating a function is exactly the same as for a stored Procedure, except a function has a RETURN clause. Use this clause to return a value to the function caller. The return value datatype is defined in the functions CREATE syntax.
CREATE [OR REPLACE] FUNCTION Function_name [(argument [{IN | OUT | IN OUT}] Datatype [{:= | DEFAULT} expression], [(argument [{IN | OUT | IN OUT}] Datatype)]

Chapter 19 3 Functions

473

RETURN return_Datatype {IS | AS} Function Body

For example, the following function returns a single value indicating the total loan fines accrued for a student:
CREATE OR REPLACE FUNCTION student_fines (student_num IN INTEGER) RETURN REAL AS book_fine REAL; total_fine REAL := 0; CURSOR scroll_fines (student_key INTEGER) IS SELECT bl_fine FROM BOOKS_LOANED WHERE bl_student_id = student_key; BEGIN Update_book_fines(student_num); OPEN scroll_fines(student_num); LOOP FETCH scroll_fines INTO book_fine; EXIT WHEN scroll_fines%NOTFOUND; total_fine := total_fine + book_fine; END LOOP; CLOSE scroll_fines; UPDATE students_fines SET sf_fine = total_fine WHERE sf_student_id = student_num; RETURN total_fine; END;

Function components
As with stored Procedures, functions are divided into two parts: the specification and the function body. The function body is analogous to an anonymous subprogram block in which the function is actually coded using PL/SQL and SQL expressions.

Specification section
CREATE [OR REPLACE] FUNCTION Function_name [(argument [{IN | OUT | IN OUT}] Datatype [{:= | DEFAULT} expression]

The CREATE OR REPLACE command replaces and creates the function specified by the function name. The CREATE FUNCTION command only creates the function requiring an existing function be dropped first by the DROP FUNCTION command. As with the stored Procedure, the inclusion of a functions parameter list is optional.
RETURN return_Datatype

474

Chapter 19 3 Procedures, Packages, Functions, and Triggers

Use the RETURN statement to pass a return value back to the caller of the function. This value is usually used as part of a callers expression. A function can have more than one RETURN statement in its function body, but only one RETURN statement is used. (Multiple exit points in a function is poor programming practice.)
Note

In stored Procedures, a RETURN statement cannot contain an expression it simply returns control to the caller before you reach the normal end of the Procedure.

Packages
A Package is a group of anonymous PL/SQL Objects, Procedures, and functions encapsulated into one logical unit. Therefore, the complete specification of certain business processes can be encapsulated into one Object. This encapsulation creates a true business Object with many interfaces, each one handling a specific business task. Like stored Procedures and functions, a Package consists of two distinct parts: the specification and the body. There is, however, a distinct difference in how Packages are created.

Creating Packages by example


The Packages specification and body are created with different commands. Listing 19-1 illustrates the creation of the specification and body sections of the library_management Package, which encapsulates some of the preceding examples.

Listing 19-1: Package library management Package specification


CREATE OR REPLACE PACKAGE library_management AS PROCEDURE loan_book (student_num IN INTEGER, book_num IN INTEGER, loan_status IN OUT VARCHAR2 ) ; PROCEDURE reserve_book (student_num IN INTEGER, book_num IN INTEGER); PROCEDURE return_book (student_num IN INTEGER, book_num IN INTEGER, book_status OUT INTEGER, fine_info OUT VARCHAR2); PRAGMA SERIALLY_REUSABLE; END library_management;

Chapter 19 3 Packages

475

Package body
CREATE OR REPLACE PACKAGE BODY library_management AS PRAGMA SERIALLY_REUSABLE; FUNCTION book_reserved (book_num IN INTEGER) RETURN INTEGER AS wait_no INTEGER := 0; BEGIN SELECT MAX(reserved_wait_no) INTO wait_no FROM books_reserved WHERE reserved_book_id = book_num; RETURN wait_no; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN wait_no; END book_reserved; PROCEDURE loan_book(student_num IN INTEGER, book_num IN INTEGER, loan_status IN OUT VARCHAR2 ) AS loan_key INTEGER; reserve_key INTEGER; book_due DATE; book_wait INTEGER; reserved_loaned EXCEPTION; BEGIN /*Check if the book is on loan or reserved */ reserve_key := book_reserved(book_num); SELECT book_loan_id INTO loan_key FROM BOOKS WHERE book_id = book_num; IF loan_key > 0 OR reserve_key > 0 THEN IF loan_key > 0 THEN -- Get the due back date of the book SELECT bl_loan_date INTO book_due FROM BOOKS_LOANED WHERE bl_loan_id = loan_key; END IF; IF reserve_key > 0 THEN -- Get the wait list on the book SELECT reserved_wait_no INTO book_wait FROM BOOKS_RESERVED WHERE reserved_id = reserve_key; END IF; RAISE reserved_loaned; ELSE -- Book is available to be loaned INSERT INTO BOOKS_LOANED VALUES ( books_on_loan.nextval, book_num, student_num, SYSDATE, 0);
(continued)

476

Chapter 19 3 Procedures, Packages, Functions, and Triggers

Listing 19-1 (Continued)


COMMIT; UPDATE BOOKS SET book_loan_id = books_on_loan.currval WHERE book_id = book_num; COMMIT; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN loan_status := The book could not be found in the Library System.; WHEN reserved_loaned THEN IF loan_key > 0 THEN loan_status := The book is currently on loan and is due for return on || (book_due + 30) || .; END IF; IF reserve_key > 0 THEN Loan_status := loan_status || || The book is reserved with a waiting list of || book_wait || persons ; END IF; END loan_book; PROCEDURE reserve_book ( student_num IN INTEGER, book_num IN INTEGER) AS wait_no INTEGER; BEGIN wait_no := book_reserved(book_num) + 1; INSERT INTO books_reserved VALUES (books_on_reserve.nextval, book_num, student_num, wait_no); END reserve_book; PROCEDURE Update_book_fines( student_num IN INTEGER) AS BEGIN UPDATE books_loaned SET bl_fine = (SYSDATE - (bl_loan_date + 30)) * .5 WHERE bl_student_id = student_num AND ((bl_loan_date + 30) < SYSDATE); END Update_book_fines; FUNCTION student_fines (student_num IN INTEGER) RETURN REAL AS book_fine REAL; total_fine REAL := 0; CURSOR scroll_fines (student_key INTEGER) IS SELECT bl_fine FROM BOOKS_LOANED WHERE bl_student_id = student_key;

Chapter 19 3 Packages

477

BEGIN Update_book_fines(student_num); OPEN scroll_fines(student_num); LOOP FETCH scroll_fines INTO book_fine; EXIT WHEN scroll_fines%NOTFOUND; total_fine := total_fine + book_fine; END LOOP; CLOSE scroll_fines; dbms_output.put_line(TO_CHAR(total_fine)); UPDATE students_fines SET sf_fine = total_fine WHERE sf_student_id = student_num; RETURN total_fine; END student_fines; PROCEDURE return_book( student_num IN INTEGER, book_num IN INTEGER, book_status OUT INTEGER, fine_info OUT VARCHAR2) AS loan_key INTEGER; student_fine REAL := 0; BEGIN -- Get the loan information SELECT book_loan_id INTO loan_key FROM books WHERE book_id = book_num; -- Get the fines due for the student student_fine := student_fines(student_num); -- Update the BOOKS table UPDATE books SET book_loan_id = 0 WHERE book_id = book_num; -- Delete the loan Record DELETE books_loaned WHERE bl_loan_id = loan_key; COMMIT; book_status := 1; fine_info := The student has a remaining fine of $ || student_fine; END return_book; END library_management;

Package components
Package specification
The specification, also known as the Package header, only contains the public definitions of its contents. The specification defines the Packages interface to the calling applications and Users.

478

Chapter 19 3 Procedures, Packages, Functions, and Triggers

The following CREATE PACKAGE command defines the specification:


CREATE [OR REPLACE] PACKAGE Package_name {IS|AS} Procedure_Specification| Function_Specification| Variable_Specification| ( can also be treated as a Global Variable) Type_definition| Exception_declaration| Cursor_declaration END [Package_name];

The name of a Package must be unique in a given Schema and both the Package specification and body must share the same name. The Package specification Objects can use similar names if Object overloading is required. (I discuss overloading in a following section.) Any defined Public Objects must be declared first. If Procedure A calls Procedure B, Procedure B must be defined in the Package specification before Procedure A. PL/SQL Objects declared in the Package specification are global they can be called or used by external Users who have EXECUTE privilege for the Package or have EXECUTE ANY PACKAGE privileges.
Note

The arguments defined for each Package specification Object must match those defined in the Package body for their respective Object declarations.

The Package body


The CREATE Package body command defines the PL/SQL code used within any declared public Object in the Package specification. The Package body can also contain private declarations, which may be necessary for the internal workings of a Package. The scope of these declarations is local to the Package body and inaccessible to any application interface. For example, the function student_ fines is local to the library_management Package and is declared before the Procedure return_book to allow forward declaration. A Package body cannot be compiled without its respective Package specification. A Package specification can be compiled separately from its respective Package body as they create separate Data Dictionary Objects. This enables the Package body to be debugged, enhanced, or replaced without recompiling the Package specification Object.

Package initialization
Following the declaration of the public and private subprograms in the Package body, an initialization section can be defined. You can use this section to initialize Package variables. You cannot pass parameters to the initialization section here and you only run it once when you execute the package for the first time.

Chapter 19 3 Packages

479

Executing Packages
When you call a Package, you actually reference one of its interfaces. To reference a Package interface, use dot notation. For example, use the following syntax to call the reserve_book Procedure within the library_management.
Package:DECLARE Student_id NUMBER := 1; Book_id NUMBER := 43; BEGIN EXECUTE library_management.reserve_book(student_id, book_id) END;

Benefits of using a Package


Packages have many benefits, especially if there is tight coupling of certain business tasks. The following reasons provide a general application development advantage to using Packages: 1. Encapsulation of related PL/SQL Objects. You can treat a Package as a whole business Object that processes a certain business task through its many public interfaces. 2. Better application design. In designing applications, you can use the Package specification initially to define the application interface, as Package specifications can be compiled without their respective Package body. When the application has matured, you can define the underlying Package body declarations. 3. Declaration of public and private Procedures. The capability to hide certain business information and processes creates a Black Box Object scenario for external Users and applications. In this scenario, Users are only aware of the publicly defined interfaces, not how the tasks are implemented themselves. 4. Better performance. When a Procedure is called within a Package, the entire Package is loaded into memory. This load is completed in one operation (as opposed to separate ones) for each defined Object in the Package specification. As a result, related Package Objects require no disk I/O to execute the compiled code in memory. 5. Better security design. Privileges are required to execute the one Package as opposed to individual privileges for each one of the publicly defined interfaces. 6. Better application maintenance. You can alter a Package body without changing its specification. Thus, you do not need to recompile Objects that reference the Package Objects via the specification. This capability stops cascading dependencies and consequently avoids recompilation.

480

Chapter 19 3 Procedures, Packages, Functions, and Triggers

7. Process retention. Packaged public Objects persist in memory for the life of a session, so they can be shared by all executing subprograms in that session. Also, these Objects data is retained across transactions without having it stored in the database.

Overloading Package interfaces


Overloading enables Procedures and functions to be defined within a Package with the same name if their formal parameters differ in numbers, order, or datatype family. This functionality is useful if you want to provide polymorphic functionality within your application the same interface to the Package will return different results.
Note

The datatypes must be in a different family, as an INTEGER datatype is in the same family as REAL datatype. Heres an example:
CREATE OR REPLACE PACKAGE overload_example AS FUNCTION Insert_Loan_Date (book_id IN INTEGER, loan_date IN DATE ); FUNCTION Insert_Loan_Date (book_id IN INTEGER, loan_date IN VARCHAR2 ); END overload_example.

The datatype of loan_date dictates which function will be called.

Package session state


Each User session that references a Package Object uses its own instance of the Package. The state for each private and public Object and variable is preserved for the life of the session. If any of the Package Objects are invalidated and recompiled, all dependent Package instantiations, including state sessions, lose their state information. Lets see an example. A session S is in progress. Session S Executes Package A. Package A then calls Package B. Both Package A and Package B reside in session S. If Package A is recompiled, both the states of Package A and Package B are lost, and the owner of session S receives an error message on the next call to Package B via Package A. The next call allows Package A and Package B to be instantiated and executed without error, however.

Serially reusable Packages


Packages normally reside in the User Global Area (UGA) of the Oracle servers memory. Since a Package state persists for the lifetime of a session, UGA memory can be consumed for long periods of time even if the Package is no longer required.

Chapter 19 3 Packages

481

A serially reusable Package has a state for the one call to the Package then its memory is deallocated and its state is destroyed. All variables initialized and set by the Package are lost. The memory allocated for serially reusable Packages is kept in a small global pool not in the UGA. This memory is used for one logical unit of work and then released back to the pool to be reused by different Users. This facility enables developers to design and deploy applications with improved scaleability and memory efficiency. To mark a Package as serially reusable, use the following PRAGMA:
PRAGMA SERIALLY_RESUABLE;

For example, if you marked the library_system Package as serially reusable, you must add the preceding PRAGMA to the specification and body section as follows:
CREATE OR REPLACE PACKAGE library_management AS PROCEDURE loan_book(student_num IN INTEGER, book_num IN INTEGER, loan_status IN OUT VARCHAR2 ) ; PROCEDURE reserve_book (student_num IN INTEGER,book_num IN INTEGER); PROCEDURE return_book(student_num IN INTEGER,book_num IN INTEGER,book_status OUT INTEGER,fine_info OUT VARCHAR2); PRAGMA SERIALLY_REUSABLE; END library_management;

Dropping Packages
The DROP PACKAGE drops the specification and the body parts of a defined Package.The Package must exist in your Schema or you must have the DROP ANY PACKAGE privilege.
Note

To drop just one construct, you have to remove it from the Package and then recompile the Package.

Oracle-supplied Packages
Oracle 8 provides built-in Packages that enable the application developer to take advantage of predefined functionality. You can treat these Packages as foundation Objects. For example, the Package UTL_HTTP allows PL/SQL to communicate with the Internet and retrieve Web pages if required. (This is a very useful Package for managing intranets and extranets.) The following Packages extend the power of PL/SQL and SQL:

482

Chapter 19 3 Procedures, Packages, Functions, and Triggers

DBMS_SESSION DBMS_TRANSACTION DBMS_SQL DBMS_UTILITY DBMS_STANDARD DBMS_OUTPUT DBMS_DDLS DBMS_ALERT UTL_HTTP UTL_FILE
CrossReference

Please refer to the Oracle reference manual for the complete syntactical usage and descriptions of these built-in Packages.

Subprogram Internals
This section enhances your knowledge about stored subprograms, which include stored Procedures, functions, and Packages.

Stored subprogram storage


When you create a stored subprogram, the PL/SQL compiler (part of the PL/SQL engine) parses the source code to produce a representation called a parse-tree. The PL/SQL compiler generates the P-code based on the parsed code. The PL/SQL engines execute the p-code when the stored subprogram is executed. Both the parsed-tree and p-code are stored in the Data Dictionary (SYSTEM Tablespace).

Validation of stored subprograms during execution


When a stored subprogram is called, Oracle initiates the following mechanism to validate the Objects execution: 1. Verify User privileges. When you invoke the execution of a stored subprogram, Oracle verifies the caller has EXECUTE privileges on that Object. The referenced Objects within the stored subprogram must be accessible to the owner of the Object. Otherwise, Oracle will reject the execution. 2. Verify Procedure validity. Oracle checks the Data Dictionary to determine whether the status of the stored subprogram is valid or invalid. Stored subprograms can be invalidated for the following reasons: Dependent Objects have been altered or recompiled since the creation of the stored subprogram.

Chapter 19 3 Subprogram Internals

483

The system privilege required by the subprogram has been revoked from PUBLIC or the stored subprogram owner. Required Object privileges for Objects referenced by the subprogram have been revoked from PUBLIC or the stored subprogram owner.

Executing a stored subprogram


When a Package, stored Procedure, or function is called, the p-code is cached into the shared pool of the SGA. This process enables the code to be executed without disk I/O and shared among other calling Users or applications. The p-code of the compiled Objects remains in the shared pool according to the Least Recently Used (LRU) rule algorithm; the p-code stays there even after the session for the Package is terminated.

Stored subprograms dependencies


The definitions of some stored subprograms may reference other Objects stored on the Oracle database. As a result, the defined Objects are dependent on the Objects referenced in their definitions. Objects that reference other Objects in their Schema are called dependent Objects while the Objects in the definition are called referenced Objects. If you alter the definition of a referenced Object, dependent Objects may or may not continue to function without an error, depending on the alteration. Oracle automatically records dependencies among Objects. All Schema Objects are given a status. The valid status is given if an Object is compiled and can be referenced. The invalid status is given to Objects that must be recompiled before they can be executed. Oracle automatically tracks specific changes in the database and records the appropriate status for the related Objects in the Data Dictionary. In the function student_fines, for example, if the Procedure Update_book_fines is recompiled, the student_fines function becomes invalid and requires recompilation or execution to become valid.
Note

Status recording is a recursive process. For example, a Package may reference a Procedure that in turn references a view that also has dependencies brought on by underlying Tables. To check if a stored subprogram is valid, view it in the Oracle Schema Manager or use the following SQL:
SELECT Object_name, Object_type, status FROM USER_OBJECTS WHERE Object_name = LOAN_BOOK

484
Caution

Chapter 19 3 Procedures, Packages, Functions, and Triggers

Oracle is case sensitive to the Object names! Oracle validates Object dependencies by using the timestamp or signatures dependency models.

Timestamp model
Timestamps are set for an Object whenever the Oracle server recompiles or creates them. Figure 19-2 examines the dependency of a Package and a stored Procedure that access a Table.

Oracle package

Procedure A Procedure C Function B

Table D

Figure 19-2: A Package and a stored Procedure that access a Table have dependencies.

If Procedure C is altered, the subprograms, Procedure A and function B within the Package, are immediately marked invalid if they are on the same server as Procedure C. The compiled states of Package A contain records of the timestamp of Procedure C. If Procedure C is altered and recompiled, its timestamp no longer matches the value recorded during the initial compilation of the Package. If Procedure C was on a different node than the Package, Procedure C is marked invalid at runtime when a call takes place from the Package. Package A would then need to be recompiled. The disadvantage of using the timestamp model is the unnecessary recompilation of dependent Objects across the network.

Chapter 19 3 Subprogram Internals

485

Signature model
To resolve the timestamp models problems of remote dependencies, Oracle provides additional capabilities using the signature model. The signature model only affects remote dependencies. The timestamp model does not affect local Objects. Recompilation is always possible. In the signature model, a subprogram contains the following attributes: 3 Name of subprogram 3 Base types of the parameters 3 Modes of the parameters Only modifications to the last two signature attributes are significant to affect a signature match. A signature is associated with each compiled PL/SQL Object and identifies the Object using the following criteria: 3 Name of the Object 3 Datatype of each parameter 3 Modes of the parameters 3 Number of parameters 3 The type of return value of a function

When does a signature change?


The following situations can cause a signature model mismatch: 1. Datatypes. A signature changes when you change the class of the datatype. (Changing a parameters datatype to another datatype within the same datatype family does not warrant a signature change.) 2. Modes. If the IN mode is added to a parameter, the default mode is just being declared and there will not be a signature mismatch. Otherwise, there will be a signature mismatch. The following situations will not cause a signature mismatch: 1. The subprogram body is changed because the specification is the same. 2. The name of a parameter is changed.

Dependency notes
3 If you change the default value in a stored subprogram, you still get the old value until the subprogram is recompiled.

486

Chapter 19 3 Procedures, Packages, Functions, and Triggers

3 If you add a new overloaded Procedure in a Package, local Procedures that call the remote Procedure are not invalidated. The Package has to recompile so that rebinding takes place for the new overloaded function to be executed. 3 In the timestamp model, if the timestamp does not match the timestamp of the called Procedure, the calling (dependent) object is invalidated and must be recompiled. If there is no local PL/SQL compiler, the calling application cannot proceed. 3 Using the signatures model, the timestamps are compared first. If they do not match, the signatures are compared. If they do not match, an error is returned to the calling application. 3 Server-side Users can use either timestamp or signature models, but if the application is distributed, the signature model avoids recompilations. 3 Client-side PL/SQL Users should set the parameter to signature. This setting enables installation of new applications at client sites without recompiling. 3 When using the signature model, add new Procedures to the end of a Package specification declaration. Otherwise, recompilation is necessary.

Dependency implementation
The User controls which dependency model to use timestamp or signature.
Note

The timestamp model is the default implemented by Oracle. If you use the signature model, you need to adjust the
REMOTE_DEPENDENCIES_MODE parameter in the init.ora file.

Syntax:
REMOTE_DEPENDENCIES_MODE=SIGNATURE|TIMESTAMP

For the all sessions:


ALTER SESSION SET REMOTE_DEPENDENCIES_MODE=SIGNATURE|TIMESTAMP

For the current session:


ALTER SYSTEM SET REMOTE_DEPENDENCIES_MODE=SIGNATURE|TIMESTAMP

Stored subprogram hiding


Deliver your Packages in Object code format using the PL/SQL wrapper. This wrapper hides your Package internals from external Users and gives Packages increased Black Box Object characteristics.

Chapter 19 3 Subprogram Internals

487

The syntax follows:


WRAP INAME = Input_file [ONAME=output_file]

The input_file is the fully qualified name of the wrapper input file. The output_file is optional because the output PL/SQL binary has the same name as the input file (except with a .plb extension).
CrossReference

For full implementation guidelines, see the Oracle reference manual.

Debugging stored subprograms


Debug stored subprograms using the DBMS_OUTPUT supplied Package. You can use the PUT and PUT_LINE statements to output the values of variables and expressions to your monitor.

Listing information about stored subprograms


Use the following methods to retrieve information about your stored subprograms. To view errors generated by compiling a stored subprogram, use the following methods:
SHOW ERRORS {PROCEDURE |FUNCTION|PACKAGE} [ , Schema].name

Example:
SHOW ERRORS PROCEDURE loan_book;

You can also use the following views to list errors with varying levels of scope: 3 USER_ERRORS 3 ALL_ERRORS 3 DBA_ERRORS To list general information about stored subprograms, use these views to view the subprogram source and other Object attributes: 3 ALL_SOURCE 3 USER_SOURCE 3 DBA_SOURCE 3 USER_OBJECT_SIZE 3 DBA_OBJECT_SIZE

488

Chapter 19 3 Procedures, Packages, Functions, and Triggers

Triggers
Triggers are similar to stored subprograms except in the following ways: 3 Triggers are implicitly executed when a Table is modified regardless of User or applications acting on the Table. 3 Triggers are defined only for database Tables. 3 Triggers do not accept arguments. 3 A Trigger can only be executed or fired by issuing the following DML actions on a Table: Update, Insert, and Delete. Triggers are paramount in the development of production data-oriented systems because they perform the following tasks: 3 Prevent invalid data transactions 3 Implement complex security 3 Enforce Referential Integrity (RI) across nodes in a distributed database 3 Create strategic and complex business rules 3 Provide transparent logging 3 Provide auditing 3 Maintain synchronous Tables 3 Gather statistics on frequently modified Tables
Note

Because Triggers can be implicitly invoked, do not introduce recursion Triggers calling other Triggers when implementing.

When to use Triggers over declarative referential integrity


One of the main reasons why Triggers are used is to facilitate RI. Oracle recommends using Triggers over Declarative Referential Integrity (DRI) only when you cannot use the following Table-level Constraints to support the application requirements:
NOT NULL UNIQUE KEY PRIMARY KEY FOREIGN KEY CHECK UPDATE UPDATE AND DELETE SET NULL UPDATE AND DELETE SET DEFAULT

Chapter 19 3 Triggers

489

Triggers also enforce RI across different nodes of a distributed database. You can use complex rules for RI that involve Triggers to control of flow statements (that is, IF.. THEN or CASE Statements).

Creating Triggers by example


Lets use the library scenario to develop a Trigger. A requirement freezes a student from borrowing a book if their book fines accrue to greater than $10.00. You could create a Trigger so that every time a students book fines are updated or inserted, the students book loan status immediately reflects the current state of the students ability to borrow books. The following Trigger illustrates this task:
CREATE OR REPLACE TRIGGER Update_student_loan_status BEFORE INSERT OR UPDATE ON STUDENTS_FINES FOR EACH ROW BEGIN IF:NEW.SF_FINE> 10 THEN UPDATE STUDENTS SET STUDENT_BL_STATUS =F WHERE STUDENTS.STUDENT_ID = :NEW.SF_STUDENT_ID; ELSE UPDATE STUDENTS SET STUDENT_BL_STATUS =T WHERE STUDENTS.STUDENT_ID = :NEW.SF_STUDENT_ID; END IF; END;

Trigger syntax
Triggers are actually made up of three distinct parts: statement, restriction, and action. The following syntax creates a Trigger:
CREATE [OR REPLACE ] TRIGGER <TRIGGER_NAME> {BEFORE|AFTER} [INSTEAD OF] TRIGGERING EVENT ON <TABLE_NAME> [FOR EACH ROW [WHEN TRIGGERING RESTRICTION]] <TRIGGER BODY>

Trigger components
A Trigger is made up of three components:

Statement
CREATE [OR REPLACE ] TRIGGER <TRIGGER_NAME> {BEFORE|AFTER} [INSTEAD OF] TRIGGERING EVENT ON <TABLE_NAME>

490

Chapter 19 3 Procedures, Packages, Functions, and Triggers

As with other stored subprograms, you can add the REPLACE keyword to the CREATE statement to drop and re-create the Trigger automatically without having to use the DROP command. The Trigger name must be a legal unique PL/SQL name in the Users Schema for Triggers. The name can be the same name as other Objects that are not Triggers, but this naming scheme causes confusion in the development and maintenance phase of any project. The timing of a Trigger, whether the Trigger is executed before or after the Triggering statement, is implemented by the BEFORE or AFTER options. The AFTER option is more efficient than the BEFORE option because affected data blocks must be logically read once for the Trigger and then for the Triggering statement. The AFTER option requires the data block to be read only once for the Trigger and the Trigger statement.
Note

The Triggering event is the SQL statement that causes the Trigger to fire, regardless of whether the Trigger is an UPDATE, DELETE, or INSERT.
BEFORE Triggers can be instrumental in deciding whether you should permit a

statement to complete. This can eliminate unnecessary processing and rollback if an exception is raised. You can also derive Column values before completing an INSERT or UPDATE operation on a Table.
AFTER Triggers validate the UPDATE, INSERT, and DELETE operations after they have taken place and allow rollback on exceptions raised.

Trigger timing permits four types of Triggers: 3 AFTER row 3 AFTER statement 3 BEFORE row 3 BEFORE statement Each Statement can either be for an UPDATE, INSERT, or DELETE operation, allowing twelve combinations of Trigger types that can be defined on one Table.
Note

If the Triggering event is an update, you can specify a Column list that needs to be modified. Because INSERT and DELETE operations affect entire rows, Column lists cannot be defined in those cases.

Handling Triggering events


A Triggering event typically consists of an INSERT, UPDATE, or DELETE operation, or a combination of these operations. In such a case, you can use conditional predicates to identify the type of statement used to invoke the Trigger. In fact, a single Trigger can accommodate all these events. Use the following predicates to control the execution of the Trigger Body:

Chapter 19 3 Triggers

491

IF Inserting then... END IF; IF Updating then... END IF; IF Deleting... END IF;

The INSTEAD OF option


New to Oracle8, this option provides a transparent way of modifying views that cannot be modified directly though INSERT, UPDATE, and DELETE statements because the underlying Tables contain joins. This Trigger option is called INSTEAD OF because Oracle fires the Trigger instead of executing the Triggering statement. The Trigger performs the SQL operations on the underlying Tables directly. Users are transparent to the Trigger because they write normal DML statements against the view and the INSTEAD OF Trigger takes care of the modifications. The INSTEAD OF option does have limitations, however, as views cannot contain the following constructs in their query: 3 Set operators 3 Group functions 3 Joins 3 Distinct

For each row


This determines whether the Trigger is a row or statement Trigger. If you specify FOR EACH ROW, the Trigger fires once for each row affected by the Trigger. Without this specification, the Trigger fires once regardless of the number of affected rows. In the Trigger body of a row Trigger, you have access to the old and new values of the current row. For UPDATE and INSERT, you have access to the old and new qualifiers, but for DELETE, only the old qualifier is available. You can use the old and new qualifiers in BEFORE and AFTER Triggers. Old and new values will only be present in the BEFORE Trigger because the statement has already taken place. If a BEFORE Trigger changes a value, the AFTER Trigger picks up the new assigned value.

The Trigger restriction


This restriction specifies a Boolean logical expression that must be true for the Trigger to fire. The Trigger is only executed if the condition is true. For example, the Update_student_loan_status Trigger could have a restriction that only allows the Trigger to execute if the student_id is less than 100:

492

Chapter 19 3 Procedures, Packages, Functions, and Triggers

CREATE OR REPLACE TRIGGER Update_student_loan_status BEFORE INSERT OR UPDATE ON STUDENTS_FINES FOR EACH ROW WHEN (NEW.SF_STUDENT_ID < 100 )

The Trigger body


Use this PL/SQL or SQL block to define the task to execute when the Trigger fires. The Trigger body can contain variables, constants, cursors, exceptions, and calls to stored Procedures.

Restrictions on creating a Trigger


The following restrictions are imposed on Trigger semantics: 3 The body can contain DML SQL statements, but SELECT statements must be SELECT INTO statements or be in cursor declarations. 3 DDL declarations are not allowed in the body of a Trigger. 3 No transaction control (commit, savepoint, or rollback statement) is allowed. 3 A called stored subprogram also cannot include transaction controls as it is executed inside the scope of a Trigger. 3 Variables of type LONG and LONG RAW cannot be used as OLD: or NEW: values.

Trigger execution
A Trigger can be executed in two modes: enabled or disabled. The enabled Trigger is executed if the restriction is true, but the disabled Trigger is not executed even if restriction is true. (By default Triggers are enabled when first created.)

Errors and Triggers


If a predefined error, User-defined error condition, or exception is raised during the execution of the Trigger body, all effects of the Trigger as well as the Triggering statement are rolled back. If a Trigger accesses a remote Table within its Trigger body and the database link is down, the Trigger compilation will fail. To resolve this problem, call a Procedure that completes the remote work, which will already be compiled locally to the Trigger.

Chapter 19 3 Triggers

493

For enabled Triggers, Oracle executes Triggers of the same type in a planned firing order when more than one Trigger is executed by a Triggering statement. Each subsequent Trigger sees changes made by the previous Triggers. Each Trigger also sees the old and new values. The old values are the original values and the new values are the current values. You may want to disable a Trigger if its referencing Object is unavailable or a large data load is to be performed. To disable a Trigger, use the following statement:
ALTER TRIGGER Trigger_name DISABLE;

To disable all Triggers associated to a Table, use the following statement:


ALTER TABLE table_name DISABLE ALL TRIGGERS;

To re-enable disabled Triggers, use the preceding command replacing the DISABLE with ENABLE.
ALTER TRIGGER Trigger_name ENABLE;
Note

To enable or disable the Triggers, you must have ALTER Schema Object privileges for the Table or have ALTER ANY TABLE system privileges.

The execution model of Triggers


A single SQL statement can potentially fire four types of Triggers: 3 BEFORE row 3 BEFORE statement 3 AFTER row 3 AFTER statement Oracle uses the following execution model to maintain the proper firing sequence of multiple Triggers and Constraint checking: 1. Execute all BEFORE statement Triggers that apply to the statement. 2. Loop for each row affected by the SQL statement. a. Execute all BEFORE row Triggers that apply to the statement. b. Lock and change row and perform integrity Constraint checking. (The lock is not released until the transaction is committed.) c. Execute all AFTER row Triggers that apply to the statement. 3. Complete deferred integrity Constraint checking. 4. Execute all AFTER statement Triggers that apply to the statement.

494

Chapter 19 3 Procedures, Packages, Functions, and Triggers

In this execution model, all actions and checks must succeed. If an exception is raised within a Trigger and the exception is not explicitly handled, all actions performed by the fired Triggers are rolled back. This execution model takes into account the integrity Constraints and disallows Triggers that violate declarative integrity Constraints.
Note

Triggers of different types fire in a particular order, but Triggers of the same type for the same firing statement are not guaranteed to fire in specific order. Do not design applications based on prerequisite Trigger processing. Although any Trigger can execute a sequence of operations via inline or by calling Procedures, using multiple Triggers of the same type enhances database administration by permitting modular installation of applications that have Triggers on the same Tables. To ensure multiple Triggered actions occur in a specific order, you must consolidate these actions by calling Procedures within a single Trigger.

Data access for Triggers


When a Trigger fires, the Tables referenced in the Trigger action may be undergoing changes by SQL statements from transactions in other sessions. The SQL in the Trigger follows the following guidelines for uncommitted transactions on a Table: 3 Queries see the current read-consistent snapshot of referenced Tables and any data changed within the current transaction. 3 Updates wait for existing data locks to be released before proceeding.

Mutating Tables
A mutating Table is a Table in the state of modification by an UPDATE, DELETE, or INSERT statement. A Table can also be updating from the effects of a declarative DELETE CASCADE referential Constraint. A constraining Table is a Table that a Triggering statement may need to read directly, via SQL statements, or indirectly for declarative referential integrity Constraints. (A Table is mutating or constraining only to the session that issued the Statement in progress.)
Note

Tables are never considered mutating or constraining for statement Triggers, unless the Trigger fires as a result of a DELETE CASCADE.

Chapter 19 3 Triggers

495

For all row or statement Triggers executed for a DELETE CASCADE, there are two restrictions regarding mutating and constraining Tables. These restrictions prevent a Trigger from viewing erroneous data because: 1. The SQL statements of a Trigger cannot read from a query or modify a mutating Table of the Triggering statement. 2. The statements of a Trigger cannot change the Primary, Foreign, or Unique Key Columns of a constraining Table of the Triggering statement.
Note

There is an exception to this restriction. If BEFORE row and AFTER row Triggers are fired by a single row insert to a Table, do not treat that Table as mutating or constraining.

Trigger maintenance and security


To create a Trigger in a Schema, one of the following statements must be true: 3 You must have the CREATE TRIGGER system privilege. 3 You must own a Table in the Trigger. 3 You must have the ALTER privilege for the Table in the Triggering statement. 3 You must have the ALTER ANY TABLE system privilege. To create a Trigger in another Users Schema, you must have the CREATE ANY Trigger system privilege. With this privilege, the Trigger can be created in any Schema and associated with any Users Table.

Modifying a Trigger
Like a stored Procedure, you cannot explicitly alter a Trigger. You must replace a Trigger with a new definition. You use the ALTER TRIGGER command only to recompile, enable, and disable a Trigger. When replacing a Trigger, you must include the OR REPLACE in the CREATE TRIGGER statement. Alternately, you can drop the Trigger using the DROP TRIGGER command and issue the CREATE TRIGGER statement again.

Privileges for referenced Schema objects


The Object privileges to the Schema Objects referenced in the Trigger body must be granted to the Triggers owner explicitly. The statements in the Trigger body operate under the domain of the Triggers owner rather than the privileges of the User who fired the Trigger. Compiled Triggers have dependencies. They become invalid if a dependent Object is modified. They are invalidated and recompiled when next invoked.

496

Chapter 19 3 Procedures, Packages, Functions, and Triggers

To examine Trigger dependencies, use the ALL_DEPENDENCIES view. For example:


SELECT Name, Referenced_owner, referenced_name, Referenced_type FROM ALL_DEPENDENCIES WHERE owner = PREM and type = Trigger;

Compiling Triggers
Triggers are similar to PL/SQL blocks with the addition of the :new and :old qualifiers, but their compilation is different. Compilation involves three stages: 1. Syntax checking. 2. Semantic checking. 3. Code generation. Triggers are fully compiled when the CREATE TRIGGER command is issued and the p-code is stored in the Data Dictionary. If errors occur during the compilation, the Trigger is still created, but all instructions to execute the Trigger fail. View the errors with the SHOW ERRORS command or SELECT the error from the USERS_ERROR view. To manually recompile a Trigger, use the ALTER TRIGGER command:
ALTER Trigger Trigger_name COMPILE;

Debugging Triggers
You can use the same debugging facilities as with other subprograms.

Listing information about Triggers


The following Data Dictionary views reveal information about Triggers: 3 USER_TRIGGERS 3 ALL_TRIGGERS 3 DBA_TRIGGERS

Understanding Subprogram Exceptions


Two types of error conditions should be handled within any production stored subprogram: 3 Internal errors 3 User-defined errors

Chapter 19 3 Understanding Subprogram Exceptions

497

Internal errors are Oracle errors returned to a PL/SQL block during execution or are caused by certain operations within the PL/SQL code (for example, divide by zero or an out-of-memory scenario). User-defined errors are explicitly defined by the developer and signaled within the PL/SQL block to control processing of errors specific to the application. When an error occurs within a stored subprogram, the following processes take place: 1. An exception is raised. 2. Normal execution of the stored subprogram stops. 3. Control transfers to the exception-handling section of the PL/SQL block. You can write specific exception handlers to handle internal or User-defined errors. 4. Control is passed back to the caller of the stored subprogram. Any variables passed by reference are not changed and all modifications are rolled back to the last COMMIT or SAVEPOINT commands.

Implementing exceptions
Internal exceptions are raised implicitly by the runtime system you do not have a choice in the matter. Oracle dictates the raising of an exception. User-defined errors, on the other hand, must be raised explicitly by the RAISE statement. By defining your own exceptions, you can also raise predefined exceptions provided by Oracle (for example, NO_DATA_FOUND). You should define User-defined exceptions in the declarative part of a PL/SQL block. Unlike internal exceptions, you must give them a name. Usually the naming scheme follows a business rule exception you want to capture, such as the reserved_loaned exception used in the stored Procedure loan_book. To handle raised exceptions, you have to code separate routines called exception handlers that process the exception according to your specific business requirements. After an exception handler runs, the current block stops executing and the enclosing block resumes with the next statement. If there is no enclosing block, control returns to the host environment.

Why use exceptions?


You should check the success or failure of every command issued within a program. The drawback in implementing this approach, however, is error processing is not clearly separated from normal processing. If you neglect to check for an error, the error could go undetected and may cause other unrelated errors the domino

498

Chapter 19 3 Procedures, Packages, Functions, and Triggers

effect. Also, your code becomes littered with repeated error checks after every command. For example:
BEGIN Select.. Check for errors Select.. Check for errors Select.. Check for errors End;

With exceptions, you can handle errors conveniently without coding multiple error checks. Exceptions also improve readability by isolating error-handling routines from the normal business logic. An example follows:
BEGIN Select.. Select.. EXCEPTION WHEN NO_DATA_FOUND THEN END;

Handling exceptions
To handle errors in your stored subprograms, you have to implement exceptionhandling routines that manage both your business-specific exceptions and Oracles internal errors.

Internal errors
As stated previously, an internal exception is raised implicitly whenever PL/SQL violates an Oracle rule or exceeds a system-dependent rule. Because every Oracle error has a number and exceptions have to be handled by name within PL/SQL, Oracle provides predefined internal exceptions. For example, the Oracle exception NO_DATA_FOUND is raised when a SELECT INTO statement returns no rows. Use the OTHERS handler to handle other errors. The error reporting functions SQLCODE and SQLERRM are especially useful in the OTHERS handler because they return the Oracle error code and message. For a complete list of predefined Oracle errors, see the Oracle reference manual.

Use defined exceptions


You can only declare exceptions in the declarative part of a PL/SQL block. The exceptions name is introduced and followed by the keyword Exception:
reserved_loaned Exception

Chapter 19 3 Understanding Subprogram Exceptions

499

After an exception is raised, control passes to the exception section of the subprogram. To direct exceptions to their respective exception control block, you must use the following structure in your code to process the error:
EXCEPTION WHEN EXCEPTION 1 THEN Sequence of Statements; WHEN EXCEPTION 2 THEN Sequence of Statements; WHEN EXCEPTION 3 THEN Sequence of Statements; WHEN OTHERS THEN

The optional OTHERS is always the last handler in a block or subprogram; there can be only one OTHERS exception. I discuss the OTHERS option later on in this chapter. If you are required to handle different exceptions with the same exception handling block, use Boolean operator OR. For example:
EXCEPTION WHEN EXCEPTION1 or EXCEPTION2.
Note

You cannot use the OTHERS option in this fashion.

Exception scope
As a rule, you cannot declare an exception twice in the same block. Exceptions declared in a block are considered local to that block and global to all its subblocks. Because a block only references local or global exceptions, enclosing blocks cannot reference the exceptions declared in subblocks.

Handling unnamed internal exceptions


To handle unnamed internal exceptions, you must use the OTHERS exception handler or the PRAGMA EXCEPTION_INIT. A PRAGMA is a compiler directive, or a parenthetical remark to the compiler. PRAGMAS are processed at compile time not at runtime. The EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number. This association enables you to refer to any internal exceptions by name and to write an appropriate exception handler by name for it. The syntax for using EXCEPTION_INIT within a subprogram follows:
PRAGMA EXCEPTION_INIT(Exception_name, oracle error number)

500

Chapter 19 3 Procedures, Packages, Functions, and Triggers

In this syntax, the exception name is the declared exception. The following example illustrates its usage:
-- Declarative section. Deadlocked_detected EXCEPTION PRAGMA EXCEPTION_INIT(Deadlocked_detected, -60) BEGIN EXCEPTION WHEN Deadlocked_detected THEN --handle the error code END;

Avoiding unhandled errors


The Raise_Application_Error command provides an error detection mechanism allowing subprograms to issue a User-defined error message back to the calling application. Use the following syntax to call Raise_Application_Error:
Raise_Application_Error(error_number, message[, TRUE|FALSE])

In this syntax, the error number is a negative number in the range -20,000 to -20,999 and the message is a character string up to 2048 bytes long. If the optional third parameter of TRUE is used, the error is placed on the stack of previous errors. If FALSE is used, the current error replaces all previous errors on the error stack.

Not handling errors


If the PL/SQL Executor cannot find a handler for a raised exception in the current block, the exception propagates the exception reproduces itself in successive blocks until a handler is found or no more blocks are available to be searched. The calling application receives an error number indicating an unhandled exception.

Summary
Today, function-rich and thin application clients that are easily maintainable and lean in terms of resource utilization are needed. This process is known as tiering. Two- and three-tier applications are moving the data processing and complex business processes away from the application client into the realms of central and database server architectures. Oracle8 provides four schema objects that facilitate the migration of the data-centric processing from the application client and into the umbrella of the Oracle8 Server. These Oracle8 schema objects are: stored Procedures, functions, Packages, and Triggers.

Chapter 19 3 Heading 1

501

From a development point, each of these Schema objects are extensible, modular, reusable, and maintainable. The richness of the Oracle8 PL/SQL language allows these Schema objects to be coded in a fashion similar to objects created in 3GL and 4GL languages. This flexibility in the code allows the Schema objects to be custom-tailored exactly to their role on the Oracle8 database server. The following key points summarize this chapter: 3 Stored Procedures and functions can be used extensively to perform complex data processing with the enhanced PL/SQL extensions to the SQL language. Although they reside in the database, stored Procedures and functions permit the creation of methods similar to those found in 3GL and 4GL languages. 3 Packages can be used to capture the behavior of a real-world Object through the encapsulation of all of its methods. Packages can be viewed as providing the interfaces to the data Object, which is the Table in the relational world. 3 Triggers, enhanced through the PL/SQL language, provide a powerful means of enforcing Constraints and complex rules on the data inserted and modified in an Oracle8 Table.

Вам также может понравиться