chapter 11dbock/cmis563/chapter…  · web view · 2007-11-30this chapter covers the creation of...

44
Chapter 13 CHAPTER 13 ----------------------------------------------------------------- ---------------------------------------------------- PROCEDURES, FUNCTIONS, PACKAGES, AND TRIGGERS This chapter covers the creation of named database objects that store executable code. Oracle subprograms include both procedures and functions. These are named PL/SQL blocks that can optionally include one or more parameters. When called, a procedure performs a data processing action can return multiple values, while a function usually performs a calculation of some sort and returns a single value to the calling procedure. The chapter also covers Oracle packages. Like procedures and functions, a package belongs to a schema. A package groups PL/SQL types, variables, exceptions, and subprograms that are logically related. Packages make it easier to develop applications by providing a named PL/SQL module with simple, well-defined interfaces. The chapter also teaches you to program database triggers. Triggers are PL/SQL blocks that execute for predefined database events, such as the insertion of a row in a database table. Triggers are useful for activities such as the automation of data archiving and the enforcement of complex data integrity rules. OBJECTIVES OBJECTIVES In this chapter, you will learn the basic skills required to: Create and drop procedures – includes passing parameters and values. Create and drop functions – includes returning values. Create package specifications, package bodies, stored, packages, cursor processing in packages, and calling stored packages. Create, alter, drop, enable, and disable triggers – includes before and after triggers. Revised: 11-28-07 13 - 1

Upload: truonganh

Post on 20-May-2018

219 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

CHAPTER 13---------------------------------------------------------------------------------------------------------------------

PROCEDURES, FUNCTIONS, PACKAGES, AND TRIGGERS

This chapter covers the creation of named database objects that store executable code. Oracle subprograms include both procedures and functions. These are named PL/SQL blocks that can optionally include one or more parameters. When called, a procedure performs a data processing action can return multiple values, while a function usually performs a calculation of some sort and returns a single value to the calling procedure.

The chapter also covers Oracle packages. Like procedures and functions, a package belongs to a schema. A package groups PL/SQL types, variables, exceptions, and subprograms that are logically related. Packages make it easier to develop applications by providing a named PL/SQL module with simple, well-defined interfaces.

The chapter also teaches you to program database triggers. Triggers are PL/SQL blocks that execute for predefined database events, such as the insertion of a row in a database table. Triggers are useful for activities such as the automation of data archiving and the enforcement of complex data integrity rules.

OBJECTIVESOBJECTIVES

In this chapter, you will learn the basic skills required to:

Create and drop procedures – includes passing parameters and values. Create and drop functions – includes returning values. Create package specifications, package bodies, stored, packages, cursor processing in

packages, and calling stored packages. Create, alter, drop, enable, and disable triggers – includes before and after triggers.

PROCEDURES AND FUNCTIONSPROCEDURES AND FUNCTIONS

Both procedures and functions are classified as Oracle subprograms. Both procedures and functions can be programmed to perform a data processing task. Functions are typically coded to perform some type of calculation. Both procedures and functions are named PL/SQL blocks, and both can be coded to take parameters to generalize the code. Both can be written with declarative, executable, and exception sections. The primary difference is that procedures are called with PL/SQL statements while functions are called as part of an expression. If this is not clear at this time, do not worry because the examples throughout this chapter will clarify these two different types of subprograms.

In previous chapters, you worked with anonymous PL/SQL blocks. Now you will learn to created named blocks that are stored as database objects. Procedures and functions are normally stored in the database within package specifications – a package is a sort of wrapper for a group of named blocks. Procedures and functions can also be stored as individual database objects. A procedure or function is parsed and compiled at the time it is stored. As a result, these coded objects tend to execute faster when compared to nonprocedural SQL scripts because nonprocedural scripts require extra time for compilation.

Revised: 11-28-07 13 - 1

Page 2: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

Procedures and functions can be invoked from most Oracle tools like SQL*Plus, and from other programming languages like C++ and JAVA. The benefits of creating these types of stored database objects include:

Improved data security. Improved data integrity. Improved application performance. Improved maintenance.

The use of named procedures and functions improves data security in two ways. This approach controls the access to base database objects such as the tables that store data. The creation of procedures and functions enables non-privileged application users to access data, but limits the access to that provided through the use of procedures and functions.

Data integrity is improved by ensuring that related actions on database tables are performed together, as a unit, by funnelling actions for related tables through a single path of access and execution. This is termed transaction integrity – either all updates that comprise a transaction are executed or none of them are executed.

Application performance is improved in several ways. First, the ability to store procedures and functions as compiled objects avoids reparsing the objects for multiple users by exploiting the capabilities of shared SQL for an Oracle database. Because the PL/SQL has already been parsed and compiled, this avoids parsing at runtime. Bundling the SQL and PL/SQL statements into procedures and functions reduces the number of database calls made, thus reducing network traffic. All statements in procedures and functions are passed to a database together as a single object.

Application maintenance is improved. Procedures and functions can be modified online without interfering with the work of other developers and application users. Single procedures and functions that perform common tasks can be modified without having to directly work on multiple applications that may call these common procedures and functions. Additionally, this approach eliminates duplicate testing that might otherwise take place.

PROCEDURESPROCEDURES

Procedures are simply named PL/SQL blocks. They are created and owned by a particular schema, usually the schema of the programmer developing the object. Like the commonly used DML functions such as COUNT() and SUM(), the privilege to execute a specific procedure can be granted to or revoked from application users in order to control data access.

Before creating procedures, the Oracle privileged user named SYS (a username often used by database administrators) must execute a SQL script named DBMSSTDX.SQL. The script is commonly run during the initial creation of an Oracle database and so it is of little consequence to you as an application developer. As a developer, you cannot create procedures until you are granted the CREATE PROCEDURE system privilege by your database administrator. If you are granted the CREATE ANY PROCEDURE system privilege, then you can create procedures within the schemas belonging to other database users. Similarly, to replace a procedure in another database user’s schema, you require the ALTER ANY PROCEDURE system privilege.

Revised: 11-28-07 13 - 2

Page 3: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

Create Procedure Syntax

The general syntax to create (or replace) a procedure is shown here. The reserved words and clauses surrounded by square brackets are optional.

CREATE [OR REPLACE] PROCEDURE <procedure_name> (<parameter1_name> <mode> <data type>, <parameter2_name> <mode> <data type>, ...) {AS|IS} <Variable declarations>BEGIN Executable statements[EXCEPTION Exception handlers]END <optional procedure name>;

Let us examine each of the clauses and options in detail. The CREATE PROCEDURE keywords specify to create a procedure with the specified <procedure name> value. The rules for naming a procedure are the same as for naming other Oracle database objects. The OR REPLACE optional clause recreates a procedure if it already exists while maintaining any procedure privileges previously granted to database user accounts. This is useful for modifying a procedure since procedures cannot be altered, they must be dropped and then recreated. If you omit the OR REPLACE keywords and the procedure already exists, then the CREATE statement fails with Oracle error message ORA-00955: name is already used by an existing object. If you omit the OR REPLACE keywords, then you must drop the procedure and create it again in order to modify the procedure. For this reason, it is a good idea to use OR REPLACE, keeping in mind that you may accidentally replace a procedure that you do not intend to replace!

Procedures are generalized by passing parameter values to them. Parameters are enclosed within parentheses. Parameters must have unique names within the procedure. When they contain more than one parameter specification, they are separated by commas. The keyword AS is required. You can optionally use the keyword IS instead of AS – they work identically.

Variables are declared within named procedures in the same fashion as you learned in anonymous PL/SQL blocks. This also applies to constants, cursors, and other objects created within a procedure to facilitate data processing. Unlike parameters, variables can be declared by specifying data type constraints.

The executable statements that comprise a procedure are coded in the executable section of the PL/SQL block that is identified by the BEGIN keyword. Likewise, exception handlers are created in the optional exception section of the PL/SQL block that is identified by the EXCEPTION keyword.

Procedure Parts

A procedure has two parts: the specification and the body. The procedure specification begins with the keyword PROCEDURE and ends with the procedure name or a parameter list. Parameter declarations are optional. Procedures that take no parameters are written without parentheses.

The procedure body begins with the keyword IS (or AS – both IS and AS work identically) and ends with the keyword END followed by an optional procedure name. The

Revised: 11-28-07 13 - 3

Page 4: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

procedure body has three parts: a declarative part, an executable part, and an optional exception-handling part.

The declarative part contains optional local declarations. Declarations are declared between the keywords IS and BEGIN. The DECLARE keyword, which introduces declarations in an anonymous PL/SQL block, is not used.

The executable part can hold one or more coding statements. Coding statements are located BEGIN and END. If an exception-handling section is coded, then coding statements for the executable part are located between the BEGIN and EXCEPTION keywords. At least one statement must appear in the executable part of a procedure. The NULL statement meets this requirement.

The exception-handling part contains exception handlers. The code for these is located between the keywords EXCEPTION and END just as you learned for an anonymous PL/SQL block.

Prior to executing a procedure, you must compile and load the procedure into a schema. In other words, you have to make it “available” in your logon session. The syntax for compiling a schema is shown here. You can use either the “@” symbol or the START SQL command to compile the file. The <SQL filename> parameter is the .sql file that contains the procedure to be compiled.

SQL>@<SQL filename>

or SQL>start <SQL filename>

This is the same command that you used to execute an anonymous PL/SQL block. It is important to understand that the filename does not need to be the same as the procedure name. The .sql file only contains the procedure code. If the procedure compiles correctly, it is then stored in the database, not the .sql file. In order to execute a procedure at the SQL prompt, you need to execute the procedure, not the .sql file. We will return to this topic later in the chapter.

Often a procedure will not compile correctly. In this situation, you will usually be prompted with a warning message. In order to examine the warning, issue the command SHOW ERRORS at the SQL> prompt.

SQL> show errors;

Procedures stored in an Oracle database as database objects are executed with the EXECUTE (EXEC for short) command. The example command shown here executes a procedure named Insert_Employee.

EXECUTE Insert_Employee

Parameters

Both procedures and functions can take parameters. Values passed as parameters to a procedure as arguments in a calling statement are termed actual parameters. The parameters in a procedure declaration are called formal parameters. The difference between these two classifications is critical to understanding the use of the parameter modes. The values stored in actual parameters are values passed to the formal parameters – the formal parameters are like Revised: 11-28-07 13 - 4

Page 5: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

placeholders to store the incoming values. When a procedure completes, the actual parameters are assigned the values of the formal parameters. A formal parameter can have one of three possible modes: (1) IN, (2), OUT, or (3) IN OUT. These modes are outlined in Table 13.1.

Table 13.1Mode DescriptionIN This type of parameter is passed to a procedure as a read-only value

that cannot be changed within the procedure.OUT This type of parameter is write-only, and can only appear on the left

side of an assignment statement in the procedure.IN OUT This type of parameter combines both IN and OUT; a parameter of this

mode is passed to a procedure, and its value can be changed within the procedure.

A formal parameter coded as mode IN receives an actual parameter value, and within the procedure, the value of the formal parameter cannot be changed. It is read-only and acts like a constant value. Mode IN is the default.

A formal parameters coded as OUT is not passed the value of the corresponding actual parameter. Rather, it behaves like an un-initialized PL/SQL variables and is assigned a NULL value. These parameters can have their value changed within a subprogram and the value of the formal parameter is returned to the actual parameter in the calling procedure.

The IN OUT mode combines both IN and OUT. The value of an actual parameter is passed to the corresponding formal parameter. In the subprogram, the formal parameter is like an initialized PL/SQL variable and it can be modified within the subprogram. When the subprogram finishes, the value of the formal parameter is passed back to the corresponding actual parameter. A good programming practice is to use different names for actual and formal parameters.

When you call a procedure, the actual parameters are evaluated and the results are assigned to the corresponding formal parameters. If necessary, before assigning the value of an actual parameter to a formal parameter, PL/SQL converts the data type of the value. For example, if you pass a number when the procedure expects a string, PL/SQL converts the parameter so that the procedure receives a string. The actual parameter and its corresponding formal parameter must have compatible data types. For instance, PL/SQL cannot convert between the DATE and NUMBER data types, or convert a string to a number if the string contains extra characters such as dollar signs.

Procedures do not always return the values of OUT and IN OUT parameters. If a procedure raises an exception, the formal parameter values are not copied back to their corresponding actual parameters.

Procedures do not allow specifying a constraint on the parameter data type. For example, the following CREATE PROCEDURE statement is not allowed because of the specification that constrains the v_Variable parameter to NUMBER(2). Instead use the general data type of NUMBER.

/* Invalid constraint on parameter. */CREATE OR REPLACE PROCEDURE proSample (v_Variable NUMBER(2), ...)

/* Valid parameter. */

Revised: 11-28-07 13 - 5

Page 6: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

CREATE OR REPLACE PROCEDURE proSample(v_Variable NUMBER, ...)

Consider the partially coded procedure named UpdateEquipment in PL/SQL Example 13.1. This procedure has five formal parameters named p_EquipmentNumber, p_Description, p_Cost, p_Quantity, and p_Project. Each is defined with a type declaration of %TYPE so that the formal parameters assume a data type that corresponds to the data type of the columns of the equipment table of the Madison Hospital database.

/* PL SQL Example 13.1 File: ch13-1.sql */CREATE OR REPLACE PROCEDURE UpdateEquipment ( p_EquipmentNumber IN Equipment.EquipmentNumber%TYPE, p_Description IN Equipment.Description%TYPE, p_Cost IN Equipment.OriginalCost%TYPE, p_Quantity IN Equipment.QuantityAvailable%TYPE, p_Project IN Equipment.ProjectNumber%TYPE )AS e_EquipmentNotFound EXCEPTION; v_ErrorTEXT VARCHAR2(512);BEGIN UPDATE Equipment SET Description = p_Description, OriginalCost = p_Cost, QuantityAvailable = p_Quantity, ProjectNumber = p_Project WHERE EquipmentNumber = p_EquipmentNumber; IF SQL%ROWCOUNT = 0 THEN Raise e_EquipmentNotFound; END IF;EXCEPTION WHEN e_EquipmentNotFound THEN DBMS_OUTPUT.PUT_LINE('Invalid Equipment Number: '||p_EquipmentNumber); WHEN OTHERS THEN v_ErrorText := SQLERRM; DBMS_OUTPUT.PUT_LINE('Unexpected error'||v_ErrorText);END UpdateEquipment; /

The UpdateEquipment procedure can be called from another PL/SQL block as shown in PL/SQL Example 13.2. This example declares five variables that are used as actual parameters in the statement that calls the UpdateEquipment procedure. The value of v_EquipmentNumber is passed to the formal parameter named p_EquipmentNumber, the value of v_Description is passed to the formal parameter p_Description, and so forth.

/* PL SQL Example 13.2 File: ch13-2.sql */DECLARE v_EquipmentNumber Equipment.EquipmentNumber%TYPE := '5000'; v_Description Equipment.Description%TYPE := 'Printer'; v_Cost Equipment.OriginalCost%TYPE := 172.00; v_Quantity Equipment.QuantityAvailable%TYPE := 2; v_Project Equipment.ProjectNumber%TYPE := 5;

BEGIN UpdateEquipment(v_EquipmentNumber, v_Description,

Revised: 11-28-07 13 - 6

Page 7: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

v_Cost, v_Quantity, v_Project);END; /

There are several points that you need to understand about calling a procedure and the use of parameters for this example.

The UpdateEquipment procedure is first created, compiled, and stored in the database as a compiled object.

The actual parameters are declared within PL/SQL Example 13.2 and assigned values – the assigned values here merely illustrate that the parameters would have values that are passed to the UpdateEquipment procedure.

The calling statement is a PL/SQL statement by itself and is not part of an expression – control will pass from the calling statement to the first statement inside the procedure.

Because the formal parameters in UpdateEquipment are all declared as mode IN, the values of these parameters cannot be changed within the procedure.

Comparing Anonymous PL/SQL Blocks with Procedures

In order to contrast anonymous PL/SQL blocks with procedures, let us examine the anonymous PL/SQL block in PL/SQL Example 13.3.

/* PL SQL Example 13.3 File: ch13-3.sql */DECLARE Temp_Salary NUMBER(10,2);BEGIN SELECT Salary INTO temp_Salary FROM Employee WHERE EmployeeID = '01885'; IF temp_Salary > 15000 THEN DBMS_OUTPUT.PUT_LINE('Salary > 15,000.'); ELSE DBMS_OUTPUT.PUT_LINE('Salary < 15,000.'); END IF;EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Employee not found.');END;/

The anonymous PL/SQL block in PL/SQL Example 13.3 stores a value from the Salary column of the employee table to a temporary variable named tempSalary for the employee with identifier 01885. Following this, a line of output is produced depending on the value of tempSalary.

Every time the code of the anonymous PL/SQL block executes, PL/SQL must first parse the code. Contrast this with the creation and execution of the procedure named DisplaySalary that is given in PL/Example 13.4. Since the procedure is stored to the database, it is only parsed and compiled once. Thereafter, the compiled version of the procedure is executed. The procedure only requires recompilation if it is dropped and created again.

Revised: 11-28-07 13 - 7

Page 8: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

/* PL SQL Example 13.4 File: ch13-4.sql */CREATE OR REPLACE PROCEDURE DisplaySalary IS -- create local variable with required constraint temp_Salary NUMBER(10,2); BEGIN SELECT Salary INTO temp_Salary FROM Employee WHERE EmployeeID = '01885'; IF temp_Salary > 15000 THEN DBMS_OUTPUT.PUT_LINE('Salary > 15,000.'); ELSE DBMS_OUTPUT.PUT_LINE('Salary < 15,000.'); END IF;EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Employee not found.');END DisplaySalary;/

You can create the procedure by issuing the appropriate command to run the file that stores the code to create the procedure at the SQL prompt as shown here (either @ch13-4.sql or start ch13-4.sql). Alternatively, you can copy/paste the entire CREATE PROCEDURE statement (including all code) within SQL*Plus and execute the code. This will also create the procedure. A successful creation results in the Procedure created message. The procedure can be executed with the exec <procedure name> command. Here the procedure is executed and the output displayed is: Salary > 15,000.

SQL> @ch13-4.sql

Procedure created.

SQL> exec DisplaySalarySalary > 15,000.

PL/SQL procedure successfully completed.

Passing IN and OUT Parameter

As you learned earlier, in order to pass values to and return values from a procedure, you need to define variables in the implicit declaration section of a procedure. PL/SQL Example 13.5 provides an example with IN and OUT variables.

/* PL SQL Example 13.5 File: ch13-5.sql */CREATE OR REPLACE PROCEDURE DisplaySalary2(p_EmployeeID IN CHAR, p_Salary OUT NUMBER)IS v_Salary NUMBER(10,2);BEGIN SELECT Salary INTO v_Salary FROM Employee WHERE EmployeeID = p_EmployeeID; IF v_Salary > 15000 THEN

Revised: 11-28-07 13 - 8

Page 9: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

DBMS_OUTPUT.PUT_LINE('Salary > 15,000.'); ELSE DBMS_OUTPUT.PUT_LINE('Salary <= 15,000.'); END IF; p_Salary := v_Salary; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Employee not found.'); END DisplaySalary2;/

In this revision of the DisplaySalary procedure, two formal parameters correspond to actual parameters of a calling procedure – p_EmployeeID as an IN parameter and p_Salary as an OUT parameter. The value of p_EmployeeID is received from the actual parameter while the value of p_Salary is initially assigned a value of NULL. A local variable named v_Salary is created and the SELECT statement stores a value to this variable from the employee table. The output displayed by the procedure depends upon whether or not the salary is greater than or less than the $15,000 salary cut-off level. Before exiting, the value of v_Salary is assigned to the p_Salary OUT parameter.

You can test calling the procedure by executing the anonymous PL/SQL block shown in PL/SQL Example 13.6. This PL/SQL block declares a parameter variable named v_Salary and then calls the procedure by providing a value of 01885 for the p_EmployeeID IN formal parameter and the parameter variable v_Salary for the p_Salary OUT formal parameter. Note that while the variable v_Salary in the calling procedure is the same name as the variable v_Salary in the DisplaySalary2 procedure, these are, in fact, two completely different local variables. The output produced to the computer monitor screen consists of one line of output produced by the stored procedure (Salary > 15,000.) and a second line of output that displays the value of the salary that is returned to the calling anonymous PL/SQL block (Actual salary: 16250).

/* PL SQL Example 13.6 File: ch13-6.sql */DECLARE v_SalaryOutput NUMBER := 0;BEGIN -- call the procedure DisplaySalary2('01885', v_SalaryOutput); -- display value of salary after the call DBMS_OUTPUT.PUT_LINE('Actual salary: '||TO_CHAR(v_SalaryOutput));END;/

Salary > 15,000.Actual salary: 16250

PL/SQL procedure successfully completed.

Using Bind Variables

Let us review PL/SQL Examples 13.5 and 13.6 again. The DisplaySalary2 procedure takes two parameters, one IN variable and one OUT variable? In PL/SQL Example 13.6 the

Revised: 11-28-07 13 - 9

Page 10: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

variable v_SalaryOutput to hold the output value returned from the procedure. The short anonymous PL/SQL block in PL/SQL Example 13.6 is used to test the DisplaySalary2 procedure. However, another approach can be used to test a procedure. This approach uses a bind variable in Oracle.

A bind variable is a variable created at the SQL*Plus prompt that is used to reference variables in PL/SQL subprograms. When you create a bind variable in SQL*Plus, you can use it like a variable in a PL/SQL programs and access the variable from SQL*Plus.

A bind variable is created at the SQL> prompt with the var statement as shown in PL/SQL Example 13.7. The procedure is quickly executed with the EXEC statement. In the EXEC statement, two parameter values are passed to the called procedure (1) a employee identifier of 01885 and (2) the v_SalaryOutput bind variable. A bind variable used in this fashion must be prefixed with a colon “:” – this syntax is required; otherwise, Oracle will return a PLS-00201: identifier 'V_SALARYOUTPUT' must be declared error message. You can examine the value returned to the variable with a PRINT statement.

/* PL SQL Example 13.7 */SQL> var v_SalaryOutput NUMBER;SQL> EXEC DisplaySalary2('01885', :v_SalaryOutput);Salary > 15,000.

PL/SQL procedure successfully completed.

SQL> PRINT v_SalaryOutput;

V_SALARYOUTPUT-------------- 16250

Dropping a Procedure

The SQL statement to drop a procedure is the straight-forward DROP PROCEDURE <procedureName> command. Keep in mind that this is a data definition language (DDL) command, and so an implicit commit executes prior to and immediately after the command.

SQL> DROP PROCEDURE DisplaySalary2;Procedure dropped.

FUNCTIONSFUNCTIONS

In PL/SQL, there is little difference between function and procedure subprograms. The primary difference is that a function can return only a single value and values are returned through use of a RETURN statement.

Create Function Syntax

Like a procedure, a function can accept multiple parameters, and the data type of the return value must be declared in the header of the function. The general syntax to create (or replace) a function is shown here. As with procedures, the reserved words and clauses surrounded by square brackets are optional.

Revised: 11-28-07 13 - 10

Page 11: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

CREATE [OR REPLACE FUNCTION] <function_name> (<parameter1_name> <mode> <data type>, <parameter2_name> <mode> <data type>, ...) RETURN <function return value data type> {AS|IS} <Variable declarations>BEGIN Executable Commands RETURN (return_value); . . .[EXCEPTION Exception handlers]END;

The general syntax of the RETURN statement is:

RETURN <expression>;

The <expression> in a RETURN statement is the value returned by the function. The RETURN statement returns the value and program control to the calling environment. It is not necessary for the RETURN statement to appear in the last line of the executable section. Further, the code may contain more than one RETURN statement, but only one RETURN statement can execute. A function that ends without executing a RETURN statement will generate an error. As with procedures, the OR REPLACE clause is optional.

PL/SQL Example 13.8 creates the RetrieveSalary function – an example function that has no parameters. When a subprogram (procedure or function) has no parameters, the object is declared without the parentheses that normally enclose the parameter list. The RetrieveSalary function retrieves the employee salary for a specific employee into the variable named v_Salary and then returns the value of that variable..

/* PL SQL Example 13.8 File: ch13-8.sql */CREATE OR REPLACE FUNCTION RetrieveSalary RETURN NUMBERIS v_Salary NUMBER(10,2);BEGIN SELECT Salary INTO v_Salary FROM Employee WHERE EmployeeID = '01885'; RETURN v_Salary;END RetrieveSalary;/

You create functions just as you did with procedures by issuing either a @<function name> or start<function name> statement at the SQL prompt as shown in PL/SQL Example 13.9. You can also copy/past the code for a function to the SQL prompt. You can test the RetrieveSalary function by using a bind variable.

/* PL SQL Example 13.9 */SQL> @RetrieveSalary

Function created.

Revised: 11-28-07 13 - 11

Page 12: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

SQL> var v_SalaryOutput NUMBER;SQL> EXEC :v_SalaryOutput := RetrieveSalary;

PL/SQL procedure successfully completed.

SQL> print v_SalaryOutput;

V_SALARYOUTPUT-------------- 16250

PL/SQL Example 13.9 illustrates a function that has a single IN parameter and that returns a VARCHAR2 data type. This function accepts the EmployeeID column value and returns the full name of the employee including the last name, first name, and middle initial. Four local variables are used in the function. The v_FullName variable stores the computed value of the full name while the other three local variables store column values selected from the employee table. An IF statement adds the middle initial if the employee has a middle name that is at least one character in length.

/* PL SQL Example 13.9 File: ch13-9.sql */CREATE OR REPLACE FUNCTION FullName(p_EmployeeID IN employee.EmployeeID%TYPE) RETURN VARCHAR2 IS v_FullName VARCHAR2(100); v_FirstName employee.FirstName%TYPE; v_MiddleName employee.MiddleName%TYPE; v_LastName employee.LastName%TYPE;BEGIN SELECT FirstName, MiddleName, LastName INTO v_FirstName, v_MiddleName, v_LastName FROM Employee WHERE EmployeeID = p_EmployeeID;

-- Store last name, comma and blank and first name to variable v_FullName := v_LastName||', '||v_FirstName;

-- Check for existence of a middle name IF LENGTH(v_MiddleName) > 0 THEN v_FullName := v_FullName||' '||SUBSTR(v_MiddleName,1,1)||'.'; END IF;

RETURN v_FullName;END FullName;/

A simple SELECT statement executed within SQL*Plus can return the full name for any employee identifier value as shown in PL/SQL Example 13.10.

/* PL SQL Example 13.10 */SQL> SELECT FullName('01885') 2 FROM Employee 3 WHERE EmployeeID = '01885';

Revised: 11-28-07 13 - 12

Page 13: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

FULLNAME('01885')-----------------------------------Bock, Douglas B.

The function is quite versatile as illustrated in this SELECT statement of PL/SQL Example 13.11 that selects all employee table rows and orders the output alphabetically.

/* PL SQL Example 13.11 */SQL> SELECT FullName(EmployeeID) 2 FROM Employee 3 ORDER BY FullName(EmployeeID);

FULLNAME(EMPLOYEEID)-------------------------------------Adams, Adam A.Barlow, William A.Becker, Robert B.Becker, Roberta G.Bock, Douglas B.... more rows will display

Dropping a Function

As with the DROP PROCEDURE statement, the DROP FUNCTION <functionName> is also straight-forward. As with DROP PROCEDURE, the DROP FUNCTION statement is a DDL command that causes execution of an implicit commit prior to and immediately after the command.

SQL> DROP FUNCTION FullName;Function dropped.

PACKAGESPACKAGES

A package is a collection of PL/SQL objects grouped together under one package name. Packages provide a means to collect related procedures, functions, cursors, declarations, types, and variables into a single, named database object that is more flexible than the related database objects are by themselves.

Consider the use of variable. All of the variables that you have used thus far in procedures and functions are local variables, meaning they are visible only in the subprogram in which they are declared. As soon as the subprogram terminates, the variable goes out of scope and the memory allocated to the subprogram for the variable is returned for reuse by the computer operating system. The variable cannot be accessed again. Sometimes it is useful and even necessary to create global variables that store values to be shared among many PL/SQL subprograms. A global variable is declared within a package by using the same syntax used to declare a local variable. While local variables are declared in the DECLARE section of an individual subprogram, global variables are declared in the DECLARE section of a package.

Revised: 11-28-07 13 - 13

Page 14: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

Package Specification and Scope

A package consists of a package specification and a package body. The package specification, also called the package header, declares global variables, cursors, exceptions, procedures, and functions that can be called or accessed by other program units.

A package specification must be a uniquely named database object. Elements of a package can declared in any order. If element “A” is referenced by another element, then element “A” must be declared before it is referenced by another element. For example, a variable referenced by a cursor must be declared before it is used by the cursor.

Declarations of subprograms must be forward declarations. This means the declaration only includes the subprogram name and arguments, but does not include the actual program code. The code of a subprogram that is part of a package is placed in the package body.

Create Package Syntax

Basically, a package is a named declaration section. Any object that can be declared in a PL/SQL block can be declared in a package. To create a package specification, use the CREATE OR REPLACE PACKAGE clause. Include the specification of each named PL/SQL block header that will be public within the package. Procedures, functions, cursors, and variables that are declared in the package specification are global. The basic syntax for a package is:

CREATE [OR REPLACE PACKAGE[ <package name> {AS|IS} <variable declarations>; <cursor declarations>; <procedure and function declarations>;END <package name>;

To declare a procedure in a package, you must specify the procedure name, followed by the parameters and variable types using the following format:

PROCEDURE <procedure_name> (param1 param1datatype, param2 param2datatype, ...);

To declare a function in a package, you must specify the function name, parameters and return variable type using the following format:

FUNCTION <function_name> (param1 param1datatype, param2 param2datatype, ...)RETURN <return data type>;

Package Body

A package body contains the code for the subprograms and other constructs, such as exceptions, that are declared in the package specification. The package body is optional. A package that contains only variable declarations, cursors, and the like, but no procedure or function declarations does not require a package body.

Revised: 11-28-07 13 - 14

Page 15: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

Any subprograms declared in a package must be coded completely in the package body. The procedure and function specifications of the package body must match the package declarations including subprogram names, parameter names, and parameter modes.

Create Package Body Syntax

Use the CREATE OR REPLACE PACKAGE BODY clause to create a package body. The basic syntax is:

CREATE [OR REPLACE] PACKAGE BODY <package_name> AS <cursor specifications> <subprogram specifications and code>END <package name>;

An Example Package

PL/SQL Example 13.12 contains the code for a package named ManageEmployee. The package specification includes declarations for a procedure named FindEmployee and a function named GoodIdentifier. It also declares an exception named e_EmployeeIDNotFound that can be raised by the FindEmployee procedure, or any other procedure that may later be added to the package that requires such an exception.

/* PL SQL Example 13.12 File: ch13-12.sql */CREATE OR REPLACE PACKAGE ManageEmployee AS -- Global variable declarations go here

-- Procedure to find employees PROCEDURE FindEmployee( emp_ID IN employee.EmployeeID%TYPE, emp_FirstName OUT employee.FirstName%TYPE, emp_LastName OUT employee.LastName%TYPE);

-- Exception raised by FindEmployee e_EmployeeIDNotFound EXCEPTION;

-- Function to determine if employee identifier is valid FUNCTION GoodIdentifier( emp_ID IN employee.EmployeeID%TYPE) RETURN BOOLEAN;END ManageEmployee;/

Since the ManageEmployee package contains two forward declarations of subprograms, a package body is needed to create the subprograms. Because the PL/SQL blocks are not being created as separate database objects, they do not require a CREATE OR REPLACE clause. PL/SQL Example 13.13 gives the ManageEmployee package body.

/* PL SQL Example 13.13 File: ch13-13.sql */CREATE OR REPLACE PACKAGE BODY ManageEmployee AS -- Procedure to find employees

Revised: 11-28-07 13 - 15

Page 16: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

PROCEDURE FindEmployee( emp_ID IN employee.EmployeeID%TYPE, emp_FirstName OUT employee.FirstName%TYPE, emp_LastName OUT employee.LastName%TYPE ) AS BEGIN SELECT FirstName, LastName INTO emp_FirstName, emp_LastName FROM Employee WHERE EmployeeID = emp_ID;

-- Check for existence of employee IF SQL%ROWCOUNT = 0 THEN RAISE e_EmployeeIDNotFound; END IF; END FindEmployee;

-- Function to determine if employee identifier is valid FUNCTION GoodIdentifier( emp_ID IN employee.EmployeeID%TYPE) RETURN BOOLEAN IS v_ID_Count NUMBER; BEGIN SELECT COUNT(*) INTO v_ID_Count FROM Employee WHERE EmployeeID = emp_ID;

-- return TRUE if v_ID_COUNT is 1 RETURN (1 = v_ID_Count); EXCEPTION WHEN OTHERS THEN RETURN FALSE; END GoodIdentifier;END ManageEmployee;/

Calling Package Objects

Objects declared in a package are visible outside of a package by qualifying the object with the package name. Consider a package named ManageEmployee that contains a procedure named UpdateEmployee. The procedure can be referenced using the following syntax:

ManageEmployees.UpdateEmployee(<parameters go here>);

PL/SQL Example 13.14 is an anonymous PL/SQL block that calls the FindEmployee procedure of the ManageEmployee package. An employee identifier value is entered for the search_ID substitution variable. Note the value is entered including single-quote marks.

/* PL SQL Example 13.14 File: ch13-14.sql */ DECLARE v_FirstName employee.FirstName%TYPE;

Revised: 11-28-07 13 - 16

Page 17: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

v_LastName employee.LastName%TYPE; search_ID employee.EmployeeID%TYPE;BEGIN ManageEmployee.FindEmployee(&search_ID, v_FirstName, v_LastName); DBMS_OUTPUT.PUT_LINE('The employee name is: ' || v_LastName || ', ' || v_FirstName);EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Cannot find an employee with that ID.');END;/

When the employee identifier is valid, the code displays the employee name as shown here.

Enter value for search_id: '01885'The employee name is: Bock, Douglas

PL/SQL procedure successfully completed.

When the identifier is not valid, the exception raised within the called procedure is propagated back to the calling procedure and is trapped by the EXCEPTION section’s WHEN OTHERS clause and an appropriate message is displayed as shown here.

Enter value for search_id: '99999'Cannot find an employee with that ID.

PL/SQL procedure successfully completed.

Cursors in Packages

As you learned in Chapter 12, a cursor can populate the result set of a multiple row query. However, a cursor is static because it is tied to a specific query inside a function or procedure. The use of a cursor variable can make a cursor dynamic so that it is reusable and sharable among different procedures and functions such as those created as part of a package.

A cursor variable has data type REF CURSOR. It is like a pointer in the C language, and it points to a query work area where a result set is stored. Therefore, the cursor can be passed freely as a parameter to other subprograms.

To create a cursor variable, you have to define a REF CURSOR type. Next, you define a cursor variable of that type. In this general syntactic example, the <return_type> object represents a row in a database table.

TYPE ref_type_name IS REF CURSOR [RETURN <return_type>];

This provides an example of declaring a cursor variable that can be used to process data rows for the equipment table of the Madison Hospital database.

DECLARE TYPE equipment_Type IS REF CURSOR RETURN equipment%ROWTYPE; cv_Equipment IN OUT equipment_Type;

Revised: 11-28-07 13 - 17

Page 18: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

PL/SQL Example 13.15 demonstrates the use of REF cursors in a package named ManageEquipment. The code that creates the package specification declares a REF CURSOR type named equipment_Type. It also declares two procedures named OpenItem and FetchItem. Note that the cursor variable cv_Equipment declared in the OpenItem procedure is declared as an IN OUT parameter. This means that the variable will store an item after the procedure is executed—it is this stored value that is input to the FetchItem procedure. The code in PL/SQL Example 13.16 creates the associated package body.

/* PL SQL Example 13.15 File: ch13-15.sql */ CREATE OR REPLACE PACKAGE ManageEquipment AS -- Create REF CURSOR type TYPE equipment_Type IS REF CURSOR RETURN equipment%ROWTYPE;

-- Declare procedure PROCEDURE OpenItem(cv_Equipment IN OUT equipment_Type, p_EquipmentNumber IN CHAR);

-- Declare procedure to fetch an equipment item PROCEDURE FetchItem(cv_Equipment IN equipment_Type, equipment_Row OUT equipment%ROWTYPE);END ManageEquipment;/

/* PL SQL Example 13.16 File: ch13-16.sql */CREATE OR REPLACE PACKAGE BODY ManageEquipment AS -- Procedure to get a specific item of equipment PROCEDURE OpenItem(cv_Equipment IN OUT equipment_Type, p_EquipmentNumber IN CHAR) AS BEGIN -- Populate the cursor OPEN cv_Equipment FOR SELECT * FROM Equipment WHERE EquipmentNumber = p_EquipmentNumber; END OpenItem; PROCEDURE FetchItem(cv_Equipment IN equipment_Type, equipment_Row OUT equipment%ROWTYPE) AS BEGIN FETCH cv_Equipment INTO equipment_Row; END FetchItem;END ManageEquipment;/

The anonymous PL/SQL block in PL/SQL Example 13.17 uses procedures defined in the ManageEquipment package to print the equipment description for the equipment number assigned to the v_EquipmentNumber variable within the program. Here the value is hard-coded for illustration purposes as equipment number ‘5001’ – the program produces the description of this item of equipment: Computer, Desktop.

/* PL SQL Example 13.16

Revised: 11-28-07 13 - 18

Page 19: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

File: ch13-16.sql */DECLARE -- Declare a cursor variable of the REF CURSOR type -- declared in the ManageEquipment package item_Cursor ManageEquipment.equipment_Type; v_EquipmentNumber equipment.EquipmentNumber%TYPE; equipment_Row equipment%ROWTYPE;BEGIN -- Assign a equipment number to the variable v_EquipmentNumber := '5001'; -- Open the cursor using a variable ManageEquipment.OpenItem(item_Cursor, v_EquipmentNumber);

-- Fetch the equipment data and display it LOOP ManageEquipment.FetchItem(item_Cursor, equipment_Row); EXIT WHEN item_cursor%NOTFOUND; DBMS_OUTPUT.PUT(equipment_Row.EquipmentNumber || ' '); DBMS_OUTPUT.PUT_LINE(equipment_Row.Description); END LOOP; END;/

5001 Computer, Desktop

PL/SQL procedure successfully completed.

Advantages of Packages

Now that you have examined several packages, you have probably begun to appreciate this approach to combining related PL/SQL blocks. The advantages of packages are summarized in Table 13.2

Table 13.2Modularity A package allows you to encapsulate related subprograms—this modularity

improves an application programmer’s understanding of how the various components of an application are related.

More Flexible Application Development

To design a package application, you must first specify the objects or subprograms in a package specification. After compiling the package specification, the stored subprograms that refer to the package can be compiled. Therefore, we need not define the package body completely, until we are ready with the specification of the application. In other words, we can code and compile a package specification without its body

Package Integrity

Packages enable the coding of both private and public database objects – this approach enables you as a developer to protect the integrity of the package. For example, consider a package that consists of four subprograms, three public and one private. The package hides the definition of the private subprogram so that only the package (not the application) is affected if the subprogram definition changes. Thus, the implementation details are hidden from other users, thereby protecting the integrity of the package.

Added Public objects and cursors declared in a package specification can be shared Revised: 11-28-07 13 - 19

Page 20: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

Functionality by all procedures executed in the environment because the public objects and cursors persist for the duration of a session.

Better Performance

When an application program calls a package the first time, the entire package is loaded in the memory. Subsequent calls require no disk input/output.

DATABASE TRIGGERSDATABASE TRIGGERS

A database trigger is a stored PL/SQL program unit that is associated with a specific database table, or with certain view types. A database trigger can also be associated with a system event such as database startup. Many years ago when triggers as database objects were first created, database administrators and application developers used the term “firing” to describe an event such as the insertion of a new table row that would execute a trigger. This is how the term “database trigger” evolved.

ORACLE executes (fires) a database trigger automatically when a given SQL DML operation, such as an INSERT, UPDATE, or DELETE affects one or more rows of a table. While procedures and functions must be explicitly invoked, database triggers are implicitly invoked. Database triggers can be used to perform any of the following tasks:

Audit data modification. Log events transparently. Enforce complex business rules. Derive column values automatically. Implement complex security authorizations. Maintain replicate tables. Publish information about events for a publish-subscribe environment such as that

associated with web programming.

Like procedures and functions, triggers are named PL/SQL blocks with declarative, executable, and exception handling sections. Triggers are stand-alone database objects – they are not stored as part of a package and cannot be local to a block. Also, triggers do not accept arguments. When you create a database trigger, you will normally assume ownership of the trigger, although ownership can be transferred to another user. In order to create and test a trigger, you (not the system user of the trigger) must have appropriate access to all objects referenced by a trigger action. For example, if you create a BEFORE INSERT trigger for the employee table, then you must have the INSERT ROW privilege for the table.

There are a few limitations with database triggers. A trigger cannot contain the COMMIT, ROLLBACK, and SAVEPOINT statements. You must be careful when using triggers as the trigger may cause the coding block to execute thousands of times for a large update seriously affect SQL execution performance. Also, the trigger body cannot exceed 32K in size. Triggers larger than this can have part of their code moved to one or more compiled stored procedures that are called from the trigger.

There is no longer a limit on the number of triggers defined for a DML statement for a table. In fact, you can define two triggers of the same type for a table. You might define two different INSERT triggers for the employee table of the Madison Hospital database. When this occurs, the triggers of the same type fire sequentially.Revised: 11-28-07 13 - 20

Page 21: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

Create Trigger Syntax

The syntax for creating a trigger is shown here. The reserved words and clauses surrounded by square brackets are optional.

CREATE [OR REPLACE] TRIGGER trigger_name{BEFORE|AFTER|INSTEAD OF} triggering_event [referencing_clause] ON {table_name | view_name}[WHEN condition] [FOR EACH ROW] DECLARE Declaration statements[BEGIN Executable statementsEXCEPTION Exception-handling statements]END;

As with procedures and functions, the CREATE TRIGGER clause creates a trigger with the specified name. Additionally, the OR REPLACE clause is optional and works in the same way that it does when creating a procedure or function.

The trigger body must have at least the executable section. The declarative and exception handling sections are optional. When there is a declarative section, the trigger body must start with the DECLARE keyword. A trigger body is the PL/SQL block that contains the SQL or PL/SQL code that executes for a triggering statement. Like stored procedures, a trigger action can call SQL or PL/SQL statements, and define PL/SQL language constructs (variables, constants, cursors, exceptions, and so on).

The BEFORE, AFTER, and INSTEAD OF keywords specify when a trigger fires – before or after a triggering event, or instead of the triggering event. The BEFORE and AFTER keyword specifications apply to tables. An INSTEAD OF trigger is only applicable to views. The triggering_event references a DML statement issued against the table or view named in the ON clause. The triggering_event specifies the table name (and an optional column name) on which a trigger fires. A DML trigger specified with a BEFORE option causes Oracle to fire the trigger before executing the triggering DML statement. On the other hand, an AFTER option causes Oracle to fire a trigger after executing the triggering statement. An INSTEAD OF trigger for a view causes the triggering statement to not fire at all; instead, the triggering statement is replaced by an alternative set of one or more SQL statements within the body of the trigger.

The referencing_clause is not used very often. When used, it enables you to write code to refer to the data in the row currently being modified by a different name.

Restrictions on a trigger are set by specifying a Boolean expression with a WHEN clause, as shown in the syntax for creating triggers. The WHEN clause specifies that a trigger is to fire only when a specific condition is met. Consider the situation where a customer order for credit is quite large. A trigger might be written to require customer order approval when the credit requested exceeds a certain maximum credit level.

WHEN (new.OrderTotal > v_MaximumCredit)

Revised: 11-28-07 13 - 21

Page 22: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

When Triggers Fire

A trigger may be a ROW or STATEMENT type of trigger. If the FOR EACH ROW clause is present in the CREATE TRIGGER command, then the trigger is a ROW trigger. A ROW trigger is fired for each row affected by a triggering statement. For example, an UPDATE trigger on the employee table will fire for every row affected by an UPDATE statement. A STATEMENT trigger, however, is fired only once for the triggering statement, regardless of the number of rows affected by the triggering statement.

Oracle specifies rules for the order by which DML statements are executed and triggers are fired. The order is:

1. Executed before statement-level triggers (if there are any).2. For each row affected by a DML statement:

a. Execute before row-level triggers (if there are any).b. Execute the DML statement.c. Execute after row-level triggers (if there are any).

3. Execute after statement-level triggers (if there are any).

STATEMENT Trigger Example

PL/SQL Example 13.17 defines an example of a STATEMENT trigger because it executes only once for the associated DML statement, not for every row. The SecureEmployee trigger can fire when deleting, inserting, or updating an employee table row. This particular trigger uses the RAISE_APPLICATION_ERROR statement to inform the application user that the table is secure and cannot be modified on a weekend day (Saturday or Sunday). The table also cannot be modified prior to 8:30 a.m. or after 6:30 p.m. Remember, you can customize error conditions with the RAISE_APPLICATION_ERROR procedure to display an error number (error numbers must be between -2001 and -20999) and an appropriate error message.

/* PL SQL Example 13.17 File: ch13-17.sql */CREATE OR REPLACE TRIGGER SecureEmployee BEFORE DELETE OR INSERT OR UPDATE ON employeeBEGIN IF (TO_CHAR(SYSDATE, 'day') IN ('saturday', 'sunday')) OR (TO_CHAR(SYSDATE, 'hh24:mi') NOT BETWEEN '08:30' AND '18:30') THEN RAISE_APPLICATION_ERROR(-20500, 'Employee table is secured'); END IF;END;/

An attempt to update a row in the employee table is illustrated by this SQL statement. Oracle responds by raising the specified error. If you create and test the SecureEmployee trigger, keep in mind that it will only fire if you execute a triggering event during one of the times specified for securing the table.

SQL> UPDATE Employee SET Salary = 10 WHERE EmployeeID = '01885';UPDATE Employee SET Salary = 10 WHERE EmployeeID = '01885' *

Revised: 11-28-07 13 - 22

Page 23: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

ERROR at line 1:ORA-20500: Employee table is securedORA-06512: at "DBOCK.SECUREEMPLOYEE", line 4ORA-04088: error during execution of trigger 'DBOCK.SECUREEMPLOYEE'

ROW Trigger Example

While a ROW trigger fires once for every row processed by the triggering statement, you can access data on the row currently being processed by using two correlation identifiers named :old and :new. These are special Oracle bind variables. The PL/SQL compiler treats these two records as records of type trigger_Table_Name%ROWTYPE. These are known as pseudo records as they are not actual records in the database. To reference a column in the triggering table, use the notation shown here where the ColumnName value is a valid column in the triggering table.

:new.ColumnName:old.ColumnName

Table 13.3 summarizes the values of :old and :new pseudo records.

Table 13.3DML Statement

:old :new

INSERT Undefined – all column values are NULL as there is no “old” version of the data row being inserted.

Stores the values that will be inserted into the new row for the table.

UPDATE Stores the original values for the row being updated before the update takes place.

Stores the new values for the row – values the row will contain after the update takes place.

DELETE Stores the original values for the row being deleted before the deletion takes place.

Undefined – all column values are NULL as there will not be a “new” version of the row being deleted.

PL/SQL Example 13.18 creates a table named equipment_audit. This table will store rows that create an audit trail of modifications made to the corresponding equipment table. The equipment_audit table has a column named Action to store information about the “action” taken against the equipment table, for example, an INSERT, UPDATE-OLD, UPDATE-NEW, or DELETE. A second column named ActionDate defaults to the system date and is used to log the date/time the table modification occurs.

/* PL SQL Example 13.18 File: ch13-18.sql */CREATE TABLE Equipment_Audit ( Action VARCHAR2(10), ActionDate DATE DEFAULT SYSDATE, EquipmentNumber CHAR(4), Description VARCHAR2(25), OriginalCost NUMBER(7,2), QuantityAvailable NUMBER(4),

Revised: 11-28-07 13 - 23

Page 24: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

ProjectNumber NUMBER(4));

PL/SQL Example 13.19 creates a row trigger that fires AFTER deleting, inserting, or updating an equipment table row; further, the trigger fires FOR EACH ROW. This particular trigger creates an audit trail for modifications made to the table by writing new rows to the equipment_audit table.

/* PL SQL Example 13.19 File: ch13-19.sql */CREATE OR REPLACE TRIGGER AuditEquipment AFTER DELETE OR INSERT OR UPDATE ON Equipment FOR EACH ROWBEGIN IF DELETING THEN INSERT INTO equipment_audit VALUES ('DELETE', SYSDATE, :old.EquipmentNumber, :old.Description, :old.OriginalCost, :old.QuantityAvailable, :old.ProjectNumber); ELSIF INSERTING THEN INSERT INTO equipment_audit VALUES ('INSERT', SYSDATE, :new.EquipmentNumber, :new.Description, :new.OriginalCost, :new.QuantityAvailable, :new.ProjectNumber); ELSE -- updating -- Insert a before and after image of updates INSERT INTO equipment_audit VALUES ('UPDATE-OLD', SYSDATE, :old.EquipmentNumber, :old.Description, :old.OriginalCost, :old.QuantityAvailable, :old.ProjectNumber); INSERT INTO equipment_audit VALUES ('UPDATE-NEW', SYSDATE, :new.EquipmentNumber, :new.Description, :new.OriginalCost, :new.QuantityAvailable, :new.ProjectNumber); END IF;END;/

There are three trigger predicates that can be used to determine if a trigger is responding to a specific DML statement: INSERTING, UPDATING, and DELETING. Notice that PL/SQL Example 13.19 uses two of these in the IF-ELSIF-ELSE structure. These predicates return TRUE if the triggering statement is of the type specified; otherwise, they return FALSE.

The script in PL/SQL Example 13.20 tests the AuditEquipment trigger. The script inserts a new equipment row for an X-Ray Table, and then modifies the row by increasing the quantity available from 1 to 2 units. Finally, the row is deleted. Each DML statement in the script fires the AuditEquipment trigger. The output of the SELECT statement is listed after the script. This shows that four new rows were added to the equipment_audit table: one row for the INSERT statement, two rows for the UPDATE statement (a before and after image), and 1 row for the DELETE statement.

/* PL SQL Example 13.20 File: ch13-20.sql */-- Insert new equipment rowINSERT INTO Equipment VALUES('9000', 'X-Ray Table', 15500.00, 1, 8);COMMIT;

-- Modify equipment row

Revised: 11-28-07 13 - 24

Page 25: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

UPDATE Equipment SET QuantityAvailable = 2 WHERE EquipmentNumber = '9000';COMMIT;

-- Delete equipment rowDELETE FROM Equipment WHERE EquipmentNumber = '9000';COMMIT;

-- List rows in Equipment_Audit table.SELECT * FROM Equipment_Audit;

ACTION ACTIONDAT EQUI DESCRIPTION ORIGINALCOST QUAN PROJ---------- --------- ---- ------------ ------------ ---- ----INSERT 25-NOV-07 9000 X-Ray Table 15500 1 8UPDATE-OLD 25-NOV-07 9000 X-Ray Table 15500 1 8UPDATE-NEW 25-NOV-07 9000 X-Ray Table 15500 2 8DELETE 25-NOV-07 9000 X-Ray Table 15500 2 8

WHEN Clause

The WHEN clause only applies to ROW triggers. The body of the trigger executes only when the condition specified is met. PL/SQL Example 13.21 provides a partial outline for the logic of a trigger that includes a WHEN clause. This example checks the value of the cost of a new item of equipment to be stored in the equipment table. If the cost is too high, the action in the trigger body takes place. Note the seemingly inconsistent use of the :new bind variable in the WHEN clause. The syntax here is correct – you do not specify the colon as part of the reference to the pseudo column.

/* PL SQL Example 13.21 */CREATE OR REPLACE TRIGGER HighCost BEFORE INSERT OR UPDATE OF OriginalCost ON equipmentFOR EACH ROWWHEN (new.OriginalCost > 15000) BEGIN /* Trigger body action is coded here */ NULL;END;/

Enabling and Disabling Triggers

It is useful to be able to enable and disable triggers. For example, if you need to run a script that does a bulk load of the equipment table, you may not want to generate audit trail information regarding the bulk load. Having a table’s triggers fire can seriously degrade the performance of a bulk load operation.

An enabled trigger executes the trigger body if the triggering statement is issued. By default, triggers are enabled. A disabled trigger does not execute the trigger body even if the triggering statement is issued. The syntax for enabling and disabling triggers is:

-- Disable an individual trigger by name.ALTER TRIGGER trigger_name DISABLE;

-- Disable all triggers associated with a table.ALTER TABLE table_name DISABLE ALL TRIGGERS;

Revised: 11-28-07 13 - 25

Page 26: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

-- Enable a trigger that was disabled.ALTER TRIGGER trigger_name ENABLE;

-- Enable all triggers associated with a table.ALTER TABLE table_name ENABLE ALL TRIGGERS;

Dropping a Trigger

The DROP TRIGGER statement drops a trigger from the database. Also, if you drop a table, all associated table triggers are also dropped. The syntax is:

DROP TRIGGER trigger_name;

SUMMARYSUMMARY

In this chapter you learned to work with subprograms including named procedures and functions, create packages, and create triggers. Each of these object types is created by writing PL/SQL blocks. Packages enable you to group PL/SQL types, variables, exceptions, and subprograms that are logically related. Packages make it easier to develop applications.

Procedures and functions are very flexible named database objects that compile when first executed, and thereafter provide very fast performance for completing a task. Both procedures and functions enable you to develop database objects that can interface with an application program. Application program calls to procedures and functions ensure that database manipulation and exception-handling are securely handled by the application programming interface defined through the parameters associated with procedures and functions.

Database triggers provide the ability to manage complex business rules, establish special audit trails, and derive column values automatically. Triggers are useful for replicating tables and logging events transparently. You learned to create both STATEMENT and ROW triggers and used triggers for a common database processing task, creating an audit trail to track changes made to the data stored in a table. Now you are prepared to practice your new skills by completing the end of chapter review exercises.

REVIEW EXERCISESREVIEW EXERCISES

Learn These Terms

1. Procedure—named PL/SQL blocks.2. Functions—similar to a procedure, except that when a function is called, it returns a single

value that is assigned to a variable.3. IN—a parameter type for a parameter passed to a procedure as a read-only value that cannot

be changed within a procedure.4. OUT—a parameter type for a parameter that receives a return value from a procedure. The

value of this parameter can only appear on the left side of an assignment statement in the procedure.

5. IN OUT—a parameter type that combines the IN and OUT parameter types. The parameter value is passed to a procedure, and its value can be changed within a procedure.

Revised: 11-28-07 13 - 26

Page 27: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

6. Package body—contains the code for the subprograms declared in the package specification.7. Package specification—also called the package header, it is used to declare global variables,

cursors, procedures, and functions that can be called or accessed by other program units. 8. Trigger—a PL/SQL code block attached and executed by an event, which occurs to a

database table.9. Row Trigger—a trigger that fires once for each row that is affected by a triggering statement. 10. Statement Trigger—a trigger that fires only once for a triggering statement; thus, a statement

trigger fires once, regardless of the number of rows affected by the triggering statement.

Concepts Quiz

1. What is the distinguishing characteristic that makes functions different from procedures? (check all that apply)

a. Functions require a PRAGMA RESTRICT clause.b. Functions only take IN parameters.c. Functions are stored in the database.d. Functions require a return value.e. None of the above.

2. What statement(s) will cause control to return to the calling environment in a function?a. The raising of an exception.b. The initialization of an OUT parameter.c. Writing to a database table.d. The RETURN statement.e. None of the above.

3. If a procedure has an IN parameter, then it must have an OUT parameter.a. Trueb. False

4. If a function declares a user-defined exception but never explicitly raises the exception, which of the following is true?

a. The function will not be able to compile.b. The function will fail a parity level check.c. The exception will never be raised.d. As long as the exception has a RETURN clause, there is no error in having a user-

defined exception and not calling it.

5. IN OUT parameters are permissible in functions.a. Trueb. Falsec. The function will compile with an IN OUT parameter, but it is not advisable to use

them.

6. Assume a trigger named mytrigger already exists in the database. If you use the CREATE clause to create a trigger with the same name because you need to modify the existing

Revised: 11-28-07 13 - 27

Page 28: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

trigger, what error message is generated? Explain your answer. What approach should you take instead?

7. All procedures and functions in a package body must be declared in the package specification.

a. Trueb. False

8. The main advantages to grouping procedures and functions into packages are as follows (check all that apply):

a. It follows the trendy object method of programming.b. It is a more efficient way of utilizing the processor memory.c. It makes greater use of the security privileges of various users.d. It is a more efficient method to maximize tablespace storage.e. It keeps you on good terms with the DBA.

9. A package specification is merely a formality for other programmers to let them know what parameters are being passed in and out of the procedures and functions. It hides the program logic but in actuality it is not necessary and is incorporated into the package body.

a. Trueb. False

10. A trigger can fire for which of the following?a. Before a triggering event.b. After a triggering event.c. Before or after a triggering event.d. Instead of a triggering event.

11. How many times does a row trigger fire if a DML statement (INSERT, UPDATE, or DELETE) is issued against a table?

a. As many times as there are rows affected by the DML operation.b. Once per DML operation.c. Once for every row of the table regardless of whether the row is affected.

12. How many times does a statement trigger fire if a DML (INSERT, UPDATE, or DELETE) operation is issued against a table?

a. As many times as there are rows affected by the DML operation.b. Once per DML operation.c. Once for every row of the table regardless of whether the row is affected.

PL/SQL Coding Exercises and Questions

In answering the PL/SQL exercises and questions, submit a copy of each script that you write along with any messages that Oracle generates while executing your program code. Also list the output for any result table that is generated by your SQL statements.

Revised: 11-28-07 13 - 28

Page 29: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

1. Create a function named IncreaseSalary that takes two parameters, EmployeeID and the percentage by which a salaried employee needs their salary needs to be raised. The function should return new salary value from the employee table.

2. Create a procedure named GetQuantity that has one IN and one OUT parameter. This procedure should take in the EquipmentNumber (of the equipment table) and return the QuantityAvailable quantity value for this equipment item by use of the OUT parameter.

3. Create a procedure named EmployeeDepartment with one IN and one OUT parameter. This procedure should take in the EmployeeID column value and return the DepartmentName column value of the department to which the employee is assigned. The procedure uses the employee and department tables.

4. Write a trigger that checks the value of the QuantityAvailable column of the equipment table for every update, and displays an error message if the QuantityAvailable falls below 2.

5. Write a trigger that fires before an update of the employee table for each row and checks if the new Salary column value is below 20000 (only for salary workers). If the salary is low, write an error message to a log table. You will need to create an appropriate log table for this exercise.

6. Write a trigger on the prescription table that fires after deleting a row, and stores the information about this department into a new table named prescription_audit. The prescription_audit table should have the same structure as the prescription table with one additional column named DelDate that will store the date a prescription is deleted.

7. Create a package that has one procedure, one function, and one exception. The procedure should take as an IN parameter a value for the EmployeeID and return the employee name (concatenate the LastName and FirstName columns) and department number values. The function should take as an IN parameter a value for the employee’s SSN column and a percentage by which the employee’s WageRate column value is to be raised. If the SSN is not for a wage employee, then raise an appropriate exception. The function should return the new wage rate.

8. Create a procedure that will determine the EmployeeID of the dept manager for an employee. The procedure should take as an IN parameter a value for the EmployeeID for the employee that is supervised employee and return the EmployeeID of the department manager. Return a value of -1 if no department manager can be found.

9. Each salaried employee is to be classified according to their salary. Create a function to return the salary class for an employee given the employee’s EmployeeID value as an IN parameter. The classification scheme is as follows:

Class A: <= 10,000Class B: > 10,000 and <= 20,000Class C: > 20,000

10. Assuming each department is granted $5,000 to purchase an equipment item, create a function that can be called in order to determine if a new row can be added to the equipment table. In other words, create a Boolean function that takes the EquipmentNumber, OriginalPrice, and QuantityAvailable as parameters, and returns a TRUE if the total value (price times quantity) does not exceed the allowance; otherwise, return FALSE.

11. Create a trigger to ensure that new employees do not have a DateHired column value for their employee table row that begins on a Saturday and Sunday.

Revised: 11-28-07 13 - 29

Page 30: CHAPTER 11dbock/cmis563/Chapter…  · Web view · 2007-11-30This chapter covers the creation of named database objects that store executable code. ... PL/SQL Example 13.19 creates

Chapter 13

12. Create a trigger that will limit project assignments to 4 projects for a single employee. If there is an attempt to assign an employee to more than four projects (by adding a new row to the projectAssignment table), the trigger should display an error message instead of allowing the INSERT statement to process.

13. Create two tables named LongTermAssignment and ShortTermAssignment, both with the following columns:

Column Name Data type Size CommentsEmployeeID CHAR 5 Primary Key. Employee identifier. Also Composite

Foreign Key link to employee tableProjectNumber NUMBER 4 Primary Key. Project number. Also Composite

Foreign Key link to project table.HoursWorked NUMBER (5,1) Number of hours an employee has worked on a project.DateUpdated DATE Primary Key. Date when this row is changed.

Create a trigger that will fire for an INSERT to the projectAssignment table such that when column values for HoursWorked equals the column value for PlannedHours, the project assignment is completed. If the HoursWorked or PlannedHours is NULL, the trigger should display an appropriate message and stop processing the data row. If the HoursWorked exceeds 100 hours, insert a new record to LongTermAssignment (long term assignment history). If the HoursWorked is less than or equal to 100 hours, insert a new record to ShortTermAssignment.

14. Create a procedure that calculates the total value for the PlannedHours column across all project assignments for an employee given his or her EmployeeID value.

Revised: 11-28-07 13 - 30