Total_plsql[1]
Total_plsql[1]
PL/SQL block:
Simple PL/SQL block: Nested PL/SQL block:
Declare Declare
Variable declarations, Variable declarations,
Cursor declarations, Cursor declarations,
User defined exceptions User defined exceptions
Begin Begin
Sql statements Declare
Pl/sql statements Variable declarations,
Exception Cursor declarations,
End; User defined exceptions
Begin
Sql statements
Pl/sql statements
Exception
End;
Exception
End;
PL/SQL Block Types:
Block name Description:
Anonymous Anonymous blocks are unnamed blocks. They are declared inline at the point in an
Blocks Application where they are to be executed and are compiled each time the application
is executed. These blocks are not stored in the database. They are passed to the PL/SQL
engine for execution at runtime.
Named All the features as specified by the anonymous block. But it contains a name called a
Blocks header. It’s not reusable and not permanent. They give the specifications of the named
spaces. These blocks are convenience for variable management. These blocks make
pl/sql more clear and readable.
Sub Subprograms are complementary to anonymous blocks. They are named pl/sql blocks
programmed that are stored in the database. Because they are named and stored, you can invoke
Blocks them whenever you want, depending on your application. You can declare them either
as procedures or as functions.
PL/SQL Variables
With pl/sql, you can declare variables and then use them in sql and procedural statements. Variables
are mainly used for storage of data and manipulation of stored values.
Variables are used to store values temporarily. You can use the values stored in these variables for
processing and manipulating data. Variables can store any PL/SQL object, such as variables, types,
cursors and subprograms.
Reusability is another advantage of declaring variables. After the variables are declared, you can use
them repeatedly in an application by referring to them multiple times in various statements.
Variable name declaration have following requirements.
o must start with a letter
o can include letters or numbers
o can include special characters - such as $,_ and #
o must not contain more than 30 characters and not include reserved words
You can use variables in various ways:
o declare and initialize variables in the declaration section
o use variables and assign new values to them in executable section
o pass variables as parameters to pl/sql subprograms
o use variables to hold the output of a pl/sql subprogram
You must declare all pl/sql identifiers in the declaration section before
Referencing them in the pl/sql block.
Syntax: identifier [CONSTANT] datatype [NOT NULL] [:=|DEFAULT expr];
Identifier: it is the name of the variable.
Constant: it constrains the variable so that its value cannot change. Constants must be initialized.
Specify it is a scalar, composite, reference or LOB data type.
Not null: it constrains the variable so that it must contain a value. Not null values must be initialized.
Expr: It is any pl/sql expression that can be a literal expression, another variable, or an expression
involving operators and functions.
Declare
v_hiredates DATE;
v_deptno NUMBER(2) NOT NULL := 10;
V_location VARCHAR2(13) := 'Atlanta';
c_comm Constant Number := 1400;
PL/sql supports these four data type categories, which you can use these data types declare
variables, constants, and pointers:
Scalar These datatypes hold a single value. All datatypes other than object oriented data
types.
Composite Exactly equivalent structures in C language. They contain internal elements that
are either scalar or composite.
Reference These hold values, called pointers, which point to a storage location.
LOB These hold values, called locators, which specify the location of large objects - such
as graphics images - that are stored outside the table.
Unconditional Branching:
o “GOTO” provides the ability to jump through a program from one place to another.
o Goto can be used with complex Exception Handlers in nested blocks, to make the execution
section more readable.
o It is better to have limited usage of ‘Goto’ in programming block.
Goto label_name:
o “EXIT” statement is most commonly used to terminate LOOP statements
Exit [WHEN Boolean_condition];
Iterations:
Simple Loop: LOOP LOOP
{.statements.} monthly_value := daily_value * 31;
EXIT WHEN EXIT WHEN monthly_value > 4000;
boolean_condition; END LOOP;
END LOOP;
While Loop: WHILE condition WHILE monthly_value <= 4000
LOOP LOOP
{.statements.} monthly_value := daily_value * 31;
END LOOP; END LOOP;
For Loop: FOR loop_counter IN [REVERSE] FOR Lcntr IN 1..20
lowest_number..highest_number LOOP
LOOP LCalc := Lcntr * 31;
{.statements.} END LOOP;
END LOOP; --------------------------------------------------------------
FOR Lcntr IN REVERSE 1..15
LOOP
LCalc := Lcntr * 31;
END LOOP;
You use a simple loop when you don’t know how many times you need to loop.
You would use a WHILE Loop when you are not sure how many times you will execute the loop
body. Since the WHILE condition is evaluated before entering the loop, it is possible that the loop
body may not execute even once.
You would use a FOR Loop when you want to execute the loop body a fixed number of times.
The variable used in the for loop need not be initialized or declared. By default for loop increments
by one. For loop is used only for numbers.
Nested for loops are, for loop inside a for loop.
Exceptions:
An exception is a pl/sql error that is raised during the execution of a code block. A pl/sql block
always terminates when an exception is raised, but you can define an exception handler in the
optional EXCEPTION section of the block.
The exception handler is pl/sql code that specifies some action to take before the block ends.
Typically exceptions are raised as a result of the following:
o An error generated by the system such as an “out of memory” or “duplicate value” error
o A user action error
o A warning from the application to the user
In oracle, pl/sql exceptions can be grouped into three distinct categories:
o Predefined oracle server exceptions
o Non predefined oracle server exceptions
o User defined exceptions
An exception can either be raised implicitly by the oracle server or explicitly by the program. An
exception is raised implicitly, or automatically, by the oracle server when an oracle error occurs. You
do not have to create any code to raise such exceptions.
A predefined oracle server exception may be raised implicitly, but you do not need to declare it. A
non predefined oracle server exception can also be raised implicitly, but must be declared within the
declarative section.
Depending on the business functionality your program is implementing, you may have to explicitly
raise an exception by issuing the RAISE statement within the pl/sql block. All user defined exceptions
must be raised explicitly.
Any exception, raised implicitly or explicitly, can be handled
o By trapping it with a handler
Pl/sql exceptions can be trapped and responded to using an exception handler, as defined in the
Exception section of a pl/sql block. If the exception is raised in the executable section of the
block, processing moves to the exception handler in the Exception section of the block, and the
pl/sql block terminates successfully.
o By propagatin it to the calling environment
If an exception is raised and there is no corresponding exception handler, the pl/sql block
terminates with failure and the exception is propagated to the calling environment that is
invoking the pl/sql program.
The exception handler mechanism allows you to cleanly separate your error processing code from
your executable statements. It also implements an event driven model, as opposed to a linear code
model, for error processing in pl/sql. A specific exception is raised in some way and it is handled by
the same exception handler.
Code structure for trapping exceptions:
Each handler consist of WHEN clause, which specifies an exception name, followed by a sequence of
statements to be executed when that exception is raised. You can include any number of handlers
within an exception section to handle specific exceptions.
Exception Exception
When exception1 Then When no_data_found Then
Statement1; Statement1;
When excpetion2 Then When too_many_rows Then
Statement2; Statement2;
When Others Then When OTHERS Then
Statement3; Statement3;
The terms exception1 and exception2, refer to the standard name of a predefined exception or the
name of a user defined exception declared within the declarative section.
The terms statment1,2 refer to standard pl/sql or sql statements.
The others clause is an optional exception handling clause that traps any exceptions that have not
been explicitly handled.
Any exceptions not specified in the Exception section are not trapped unless you use the Others
exception handler, which, if it is used, must be the last exception handler that is defined.
Some of the predefined exception names include:
Access_Into_null Cursor_already_open Program_error
Too_many_rows Zero_divide Case_not_found
Invalid_cursor No_data_found Not_logged_on
Trapping non predefined exceptions in pl/sql:
To trap non predefined oracle error, u must declare first. The declared exception is raised implicitly.
In pl/sql, the PRAGMA EXCEPTION_INIT clause tells the compiler to associate an exception name
with an oracle error number. This allows you to refer to any internal exception by name and to write
a specific handler for it.
In common with many other programming languages, PRAGMA in PL/SQL is a keyword that signifies
a compiler directive, which is not processed as a pl/sql block is executed. Rather, it directs the
compiler to associate all instances of the exception name you provide with a specific oracle server
exception number.
This is the syntax for declaring, associating and referencing a non predefined oracle server exception
in a pl/sql block.
Declare Declare
Exception1 EXCEPTION; Insert_excep Exception;
Pragma Exception_Init Pragma Exception_init
(exception1, -oracle_err_no) (insert_excep, -01400);
Begin Begin
……… Insert into dept(dept_id, dept_name) values (280, null);
Exeption Exception
When exception1 Then When insert_excep Then
Statement1; Dbms_output.put_line(‘Insert Operation Failed’);
End; End;
You declare the name of the exception in the declarative section by specifying an identifier for the
exception followed by the Exception keyword.
After declaring an exception, you must associate it with a specific oracle server error number using
the program exception_init function. The arguments to this function are the exception name
followed by a valid oracle error number, which is always negative
The declared exception can be referenced in the Exception section using the same syntax as for
predefined oracle exceptions. So statement1 will only be executed if the error with the number
oracle_err_no occurs.
In the above example, you decide to display an error message, giving details of the error, and
complete this SQL block. When you execute this block, the error -01400 occurs and is converted to
the exception you declared(insert_excep), which is trapped by the corresponding exception handler,
causing the error message to be displayed.
Handling User defined exceptions:
A user defined exception is an error that is defined by the programmer. It need not be an oracle
error – it could be a data error, for example. Many problems that users encounter while using an
application are specific to that application. Defining exceptions enables you to give names to
otherwise anonymous system errors and specify how they should be handled.
Suppose you want users of an application to update department names in the Departments table.
You want the user to supply the department number and the new name. You decide to define an
exception to deal with error conditions in the input data. If the department number supplied by the
user doesn’t exist, you want to raise a user defined exception.
Declare
Invalid_departement EXCEPTION;
Name varchar2(20) := ‘&name’;
Deptno Number := &deptno;
Begin
Update departments set department_name = name where department_id = deptno;
If sql%notfound then
Raise invalid_department;
End IF;
Commit;
Exception
When invalid_department Then
Dbms_output.put_line(‘No such department id.’);
End;
You use the RAISE statement to raise the exception explicitly within the executable section of the
block. Once the exception is raised, control passes immediately to the Exception section of the block
so any code following the Raise statement is not executed. In this case, the exception is raised if the
department ID entered by the user does not exist.
You can use the When Others clause in the Exception section of a pl/sql block to trap unhandled
exceptions. Two functions can be included in the clause to determine the error code and error
message associated with the exception.
The two functions are
o SQLCODE: You use the sqlcode function to return the oracle error number for internal
exceptions. You can assign it to a NUMBER variable.
o SQLERRM: You use the sqlerrm function to return the message associated with the oracle
error number. It returns character data.
Handling exceptions in Nested Blocks:
You can use nested blocks, or subblocks, to handle exceptions in Pl/sql. When an exception is
handled in a subblock, the block terminates normally and control passes back to the enclosing block
following the subblocks END statement.
This functionality means that you can enclose statements requiring exclusive error handling inside
their own block. In addition, by handling exceptions within subblokcs, you ensure that any remaining
executable actions in the enclosing block can still execute.
Declare Declare
Qty_on_hand Number; Qty_on_hand Number;
Begin Begin
Select quantity_on_hand into qty_on_hand Begin
From inventories where product_id = 100; Select quantity_on_hand into qty_on_hand
Update product _information set product_status From inventories where product_id = 100;
= decode(qty_on_hanbd, 0, 0, product_status) Exception
Where product_id = 100; When no_data_found Then
Exception Qty_on_hand := 1;
When no_data_found Then End;
Null; Update product _information set product_status
End; = decode(qty_on_hanbd, 0, 0, product_status)
Where product_id = 100;
Exception
When no_data_found Then
Null;
End;
In this example, if the select statement retrieves no rows, pl/sql raises an exception, which is dealt
with in the exception section of the block. The update command in the executable section is
bypassed because, once the exception is raised, control passes immediately to the Exception section
of the block.
In the second you enclose the select statement in a subblock with its own exception section. In this
case, if the select statement returns no rows, the update command will still execute because the
exception is handled in the exception section of the subblock.
Raise_application_error procedure:
You use the raise_application_error procedure to raise application specific errors in your application.
The procedure allows you to communicate a predefined exception interactively by returning a
nonstandard error code and error message.
One advantage of using raise_application_error instead of raise – which can also be used to raise an
application specific, explicitly declared exception is that you can create and associate an error
message with the raised exception.
When an application calls a raise_application_error procedure from an executing stored
subprogram, raise_application_error ends the subprogram and returns the error number and
message that you’ve specified to the application. The error number and message can be trapped like
any oracle error.
Syntax: raise_appliation_error(error_number, message[,{True | False}]);
In the syntax for the procedure, you follow raise_application_error with the error number and error
message. The error number that you specify for the exception must be between -20999 to -
20000.The message you supply must be a character string of up to 2048 bytes long.
You can also optionally specify a Boolean parameter to indicate whether you want to add the error
to any already on the stackt (TRUE) or replace the existing errors(False, the default).
Cursors:
You can include sql statements that return a single row in a pl/sql block. The data retrieved by the
sql statement should be held in variables using the INTO clause.
The oracle sever allocates a private memory area called the context area for processing sql
statements. The sql statement is parsed and processed in this area. Information required for
processing and information retrieved after processing are all stored in this area. You have no control
over this area because it is internally managed by the oracle server.
A cursor is a pointer to the context area. In other words, it is a pointer to the private memory area
allocated by the oracle server.
A cursor is used to handle the result set of a select statement. However, this cursor is an implicit
cursor and is automatically managed by the oracle server.
When the executable block issues a sql statement, pl/sql creates an implicit cursor.
There are two types of cursors:
o Implicit: An implicit cursor is created and managed by the oracle server. You do not have
access to it. The oracle server creates this cursor when it has to execute a sql statement.
o Explicit: A cursor that is declared by programmers is called an explicit cursor. As a
programmer, you may want to retrieve multiple rows from a database table, have a pointer
to each row that is retrieved, and work on the rows one at a time. In such cases, you can
declare cursors explicitly depending on your business requirements. You declare an explicit
cursor in the declarative section of a pl/sql block.
Implicit Cursors:
Sql cursor attributes enable you to evaluate what happened when an implicit cursor was last used.
You can use these attributes in pl/sql statements but not in sql statements.
You can test the sql%rowcount, sql%found, sql%notfound and sql%isopen attributes in the
executable section of a block to gather information after the appropriate DML command executes.
Pl/sql does not return an error if a dml statement does not affect rows in the underlying table.
However, if a select statement does not retrieve any rows, pl/sql returns an exception.
All the attributes are prefixed with sql. These cursor attributes are used with implicit cursors that are
automatically created by pl/sql for which you do not know the names. Therefore, you use sql instead
of the cursor name.
The sql%notfound attribute is opposite to sql%found. This attribute may be used as the exit
condition in a loop. It is useful in Update and delete statements when no rows are changed because
exceptions are not returned in these cases.
Sql%found is a Boolean attribute that evaluates to True if the most recent sql statement returned at
least one row.
Sql%notfound is a Boolean attribute that evaluates to True if the most recent sql statement did not
return even one row.
Sql%rowcount is an integer value that represents the number of rows affected by the most recent
sql statement.
Sql%isopen is an Boolean attribute that evaluates to True if the cursor is open. For implicit cursor
this attribute is always false.
Explicit Cursors:
The oracle server uses work areas, called private sql areas, to execute sql statements and store
processing information. You can use explicit cursors to name a private sql area and to access its
stored information.
You declare explicit cursors in pl/sql when you have a select statement that returns multiple rows.
You can process each row returned by the select statement.
The set of rows returned by a multiple row query is called the active set. Its size is the number of
rows that meet your search criteria. Here an explicit cursor points to the current row in the active
set. This enables a program to process the rows one at a time.
These are the functions performed by an explicit cursor:
o It can perform row by row processing beyond the first row returned by a query.
o It keeps track of the row that is currently being processed.
o It enables the programmer to manually control explicit cursors in the pl/sql block.
The steps for using an explicit cursor are
o Defining the structure of the query: The first step is to define the structure of the query. In
the declarative section of a pl/sql block, you declare the cursor by naming it and defining the
structure of the query to be associated with it.
Cursor <cursorname> is <select statement>
o Opening the cursor: After declaring the cursor, you need to open the cursor to identify the
active set of rows. The OPEN statement executes the query and binds any variables that are
references. Rows identified by the query are called the active set and are available for
fetching.
Open <cursorname>
o Fetching data from the cursor: The third step involves fetching data from the cursor. After
each fetch, you test the cursor for any existing row. If there are no more rows to process,
you must close the cursor.
Fetch <cursorname> into <variable>;
o Closing the cursor: The fourth step involves closing the cursor. The close statement releases
the active set of rows. You can reopen the cursor to establish a fresh active set.
Close <cursorname>
A pl/sql program opens a cursor, processes rows returned by a query, and then closes the cursor.
The cursor marks the current position in the active set.
You perform these steps to control explicit cursors in a pl/sql program:
o Open: The open statement executes the query associated with the cursor, identifies the
active set, and positions the cursor at the first row. The open statement is included in the
executable section of the pl/sql block.
o Fetch: The fetch statement retrieves the current row and advances the cursor to the next
row until there are no more rows or a specified condition is met.
o Close: The close statement releases the cursor.
In the syntax to declare a cursor, cursor_name is the pl/sql identifier, and the select_statement is
used to identify the select statement without an into clause.
CURSOR cursor_name IS select statement;
The active set of a cursor is determined by the select statement in the cursor declaration. It is
mandatory to have an INTO clause for a select statement in pl/sql. However the select statement in
the cursor declaration cannot have an Into clause. This is because you are only defining a cursor in
the declarative section and not retrieving any rows into the cursor.
You need to consider these guide lines while declaring a cursor:
o Do not include the INTO clause in the cursor declaration because it appears later in the fetch
statement.
o If processing rows in a specific sequence is required, use the order by clause in the query.
o The cursor can be any valid select statement, including joins, sub queries and so on.
DECLARE
Cursor c_emp_cursor IS
Select employee_id, last_name From employees where dept_id = 30;
Begin
Open c_emp_cursor;
Loop
Fetch c_emp_cursor into empno, lnae;
Exit when c_emp_cursor%notfound;
Dbms_output.put_line(v_empno || ‘ ‘ || v_lname);
End loop;
Close c_emp_cursor;
End;
……..
Open is an executable statement that performs these operations:
o It dynamically allocates memory for a context area.
o It parses the select statement
o It binds the input variables and sets the values for the input variables by obtaining their
memory addresses
o It identifies the active set – the set of rows that satisfy the search criteria – rows in the
active set are not retrieved into variables when the open statement is executed, the fetch
statement retrieves the rows from the cursor to the variables.
o It positions the pointer to the first row in the active set.
The fetch statement retrieves the rows from the cursor one at a time. After each fetch, the cursor
advances to the next row in the active set. You can use the %notfound attribute to determine
whether the entire active set has been retrieved.
The fetch statement performs these operations:
o It reads the data for the current row into the output pl/sql variables
o It advances the pointer to the next row in the active set
The close statement disables the cursor, releases the context area, and undefined the active set. You
should close the cursor after completing the fetch statement processing. You can reopen the cursor
if required. A cursor can be reopened only if it is close. If you attempt to fetch data from a cursor
after it is been closed, then an Invalid cursor exception is raised.
Although it is possible to terminate the pl/sql block without closing cursors, you should ensure to
close any cursor that you declare explicitly to free up resources. There is a maximum limit on the
number of open cursors per session, which is determined by the open_cursors parameter in the
database parameter file – open_cursors = 50 by default.
You can define record that have the structure of columns in a table by using %rowtype. You can also
define a record based on the selected list of columns in an explicit cursor. This is convenient for
processing the rows of the active set, because you can simply fetch into the record. Therefore, the
values of the row are loaded directly into the corresponding fields of the record.
You can fetch data from cursors by using a simple loop, however, you can also use the cursor FOR
loop to process rows in an explicit cursor. It is a shortcut because the cursor is opened, a row is
fetched once for each iteration in the loop, the loop exits when the last row is processed, and the
cursor is closed automatically. The loop itself is terminated automatically at the end of the iteration
where the last row is fetched. In the cursor for loop, the record is implicitly declared.
Syntax:
FOR record_name IN cursor_name LOOP
Statement1;
…………….
END LOOP;
In the syntax for declaring a cursor FOR loop, record_name is the name of the implicitly declared
record and the cursor_name is the pl/sql identifier for the previously declared cursor.
You need to consider these guidelines for declaring a cursor for loop:
o Do not declare the record that controls the loop; it is declared implicitly
o Test the cursor attributes during the loop, if required
o Supply the parameters for a cursor, if required, in parenthesis following the cursor name in
the for statement.
For loop cursor:
Declare
Cursor c_emp_cursor is
Select employee_id, last_name from employees where department_id = 30;
Begin
For emp_record IN c_emp_cursor LOOP
Dbms_output.put_line(emp_record.employee_id || ‘ ‘ || emp_record.last_name);
END LOOP;
END;
The above example code that was used to show a simple loop to fetch the data from the cursors has
been rewritten here to use the cursor FOR loop. In this code, the emp_record is the record that is
implicitly declared. You can access the fetched data with the implicit record. In the code, no
variables are declared to hold the fetched data using the INTO clause. The code does not have OPEN
and CLOSE statements to open and close the cursor, respectively.
For loops using subqueries:
Begin
For emp_record in (select employee_id, last_name from employee where dept_id = 30)
Loop
Dbms_output.put_line(emp_record.employee_id || ‘ ‘ || emp_record.last_name);
END LOOP;
END;
In this code, note there is no declarative section in the pl/sql block. The difference between the
cursor for loops using subqueries and the cursor for loops using subqueries and the cursor for loop
lies in the cursor declaration. If you are writing cursor for loops using subqueries, you need not
declare the cursor in the declarative section. You have to provide the select statement that
determines the active set in the loop itself. This sample code is used to illustruate a cursor FOR loop
using subqueries.
As with implicit cursors, there are explicit cursor attributes for obtaining status information about a
cursor. When appended to the cursor variable name, these attributes return useful information
about the execution of a cursor manipulation statement.
You cannot reference cursor attributes directly in a sql statement.
The four attributes are %isopen, %notfound, %found and %rowcount
You can use the %isopen attribute and then fetch the records if the cursor is open.
You use the %rowcount cursor attribute to, process an exact number of rows and fetch the rows in a
loop and determine when to exit the loop.
Using cursors with parameters:
You can pass parameters to a cursor when the cursor is opened and the query is executed. This
means that you can open and close an explicit cursor several times in a block, returning a different
active set on each occasion. For each execution, the previous cursor is closed and reopened with a
new set of parameters. Here is the syntax for cursor declaration using parameters.
CURSOR cursor_name [(parameter_name datatype, …..}]
IS
Select statement;
Each formal parameter in the cursor declaration must have a corresponding actual parameter in the
OPEN statement. The parameter notation does not offer greater functionality; it simply allows you
to specify input values easily and clearly. This is particularly useful when the same cursor is
referenced repeatedly.
Open cursor_name(parameter_value….);
Declare
Cursor c_emp_cursor (deptno Number) IS
Select employee_id, last_name from employees where department_id = deptno;
…
Begin
Open c_emp_cursor(10);
….
Close c_emp_cursor;
Open c_emp_cursor(20);
…
In the sample code, the OPEN statements open the cursor and return different active sets.
You can also pass parameters to the cursor that is used in a cursor for loop.
Declare
Cursor c_emp_cursor(p_deptno Number, p_job varchar2) is
Select ….
Begin
For emp_record IN c_emp_cursor(10, ‘sales’) LOOP…..
REF CURSORS:
Cursor variables are like C or pascal pointer, which hold the memory location or address of some
item instead of the item itself. Thus, declaring a cursor variable creates a pointer, not an item.
In pl/sql a pointer has the data type REF X, where REF is short for REFERENCE and X stands for a class
of objects. A cursor variable has the REF cursor data type.
Like a cursor, a cursor variable points to the current row in the result set of a multirow query.
However, cursors differ from cursor variables in the same way as constants differ from variables.
A cursor is static, but a cursor variable is dynamic because it is not tied to a specific query. You can
open a cursor variable for any type compatible query. This gives you more flexibility.
Cursor variables are available to every Pl/sql client. For example, you can declare a cursor variable in
a pl/sql host environment such as an oracle call interface(OCI) or Pro*C program, and then pass it as
an input host variable or bind variable to pl/sql.
Moreover, application development tools such as oracle forms and oracle reports, which have a
pl/sql engine, can use cursor variables entirely on the client side. The oracle server also has a pl/sql
engine. You can pass cursor variables back and forth between an application and server through
remote procedure calls(RPCs).
You use cursor variables to pass query result sets between pl/sql stored subprograms and various
clients. Neither pl/sql nor any of its clients owns a result set; they simply share a pointer to the
query work area in which the result set is stored.
A query work area remains accessible as long as any cursor variable points to it. Therefore, you can
pass the value of a cursor variable freely from one scope to another.
If you have a pl/sql engine on the client side, calls from client to server impose no restrictions. For
example, you can declare a cursor variable on the client side, open and fetch from it on the server
side, and then continue to fetch from it back on the client side.
You can also reduce network traffic by having a pl/sql block open or close several host cursor
variables in a single round trip.
A cursor variable holds a reference to the cursor work area in the program global area(PGA) instead
of addressing it with a static name. Because you address this area by a reference, you gain the
flexibility of a variable.
To define a REF cursor, you perform two steps:
o You define a REF CURSOR type
o You declare cursor variables of that type
You can define REF CURSOR types in any pl/sql block, subprogram, or package using this syntax
TYPE ref_type_name IS REF CURSOR [RETURN return_type];
Ref_type_name is a type specifier used in subsequent declarations of cursor variables.
Return_type represents a record or a row in a database table.
In this sample code, you specify a return type that represent a row in the database table dept.
Declare
TYPE deptcurtyp is REF CURSOR RETURN departments%rowtype;
Dept_cf deptcurtyp;
Ref cursor types can be either strong(restrictive) or weak(nonrestrictive). In this sample code, a
strong REF CURSOR type definition specifies a return type, but a weak definition does not.
Declare
Type empcurtyp is ref cursor return employees%rowtype; ---strong
Type genericcurtyp is ref cursor; -- weak
There are two REF cursor types:
o Strong REF cursor: These types are less error prone because the pl/sql compiler lets you
associate a strongly typed cursor variable only with type compatible queries.
o Weak REF cursor: Weak ref cursor types are more flexible because the compiler lets you
associate a weakly typed cursor variable with any query.
After you define a REF CURSOR type, you can declare cursor variables of that type in any pl/sql block
or subprogram. This is the syntax to declare a cursor variable of the defined type.
Ref_cv ref_type_name;
You can declare cursor variables as the formal parameters of functions and procedures. In this
sample code, you define the REF CURSOR type EMPCURTYP, and then declare a cursor variable of
that type as the formal parameter of a procedure.
Declare
Type empcurtype is ref cursor return emp%rowtype;
Procedure open_emp_cv(emp_cv IN OUT empcurtyp) IS…..
Processing multirow queries
You use three statements to process a dynamic multirow quey: OPEN-FOR, Fetch & Close:
o You open a cursor variable for a multirow query
o You fetch rows from the result set one at a time
o When all the rows are processed, you close the cursor variable.
The open-for statement associates a cursor variable with a multirow query, executes the query,
identifies the result set, positions the cursor to point to the first row of the results set, and then sets
the rows processed count kept by %rowcount to zero.
Unlike the static form of open-for, the dynamic form has an optional using clause. At run time, bind
arguments in the using clause replace corresponding placeholders in the dynamic select statement.
This is the syntax for the open for statement.
Open {cursor_variable | :host_cursor_variable) FOR dynamic_string
[USING bind_argument [, bind_argument]…
Cursor_vairable is a weakly typed cursor variable, which is without a return type.
Host_cursor_variable is a cursor variable declared in a pl/sql host environment such as an oci prog
Dynamic string is a string expression that represents a multirow query.
Declare
Type empcurtyp is REF CURSOR; --define weak ref cursor type
Emp_cv empcurtyp; --declare cursor variable
My_ename varchar2(15);
My_sal number := 1000;
Begin
Open emp_cv for --- open cursor variable
‘select last_name, salary From employees where salary > :s’ using my_sal;
…..
End;
In this sample code, the syntax declares a cursor variable and then associates it with a dynamic
select statement that returns rows from the employees table.
Any bind arguments in the query are evaluated only when the cursor variable is opened. Therefore,
to fetch rows from the cursor using different bind values, you must reopen the cursor variable with
the bind arguments set to their new values.
The fetch statement returns a row from the result set of a multirow query, assigns the values of a
select list items to corresponding variables or fields in the INTO clause, increments the count kept by
% rowcount, and advances the cursor to the next row. This is the syntax for Fetch statement.
Fetch {cursor_variable | :host_cursor_varibale} INTO {define_varaible … | record};
Loop
Fetch emp_cv into my_ename, my_sal; -- fetch next row
Exit when emp_cv%notfound; --exit loop when last row is fetched
---process row
End loop;
In the above example, the rows are fetched from the cursor variable emp_cv into define variables
my_ename and my_sal.
For each column value returned by the query associated with the cursor variables, there must be a
corresponding type compatible variable or field in the into clause. You can use a different into clause
on separate fetches with the same cursor variable. Each fetch retrieves another row from the same
result set. If you try to fetch from a closed or never opened cursor variable, pl/sql raises the
predefined exception invalid_cursror.
The close statement disables a cursor variable. After this, the associated result set is undefined. This
is the syntax for the close statement.
Close {cursor_variable} | :host_cursor_variable};
Loop
Fetch emp_cv into my_ename, my_sal;
Exit when emp_cv%notfound; --exit loop when last row is fetched
---process row
End loop;
CLOSE emp_cv; --- close cursor variable.
In the above example, when the last row is processed, the emp_cv cursor variable is closed.
If you try to close an already closed or never opened cursor variable, pl/sql raises invalid_cursor.
Modularization:
PL/SQL is a block structured language. You can take advantage of this fact to write cleaner, more
efficient code. For example, you can reuse blocks of code instead of rewriting them every time they
are needed. The breaking up of large blocks of code into smaller, more manageable blocks – or
modules – is called modularization.
Modularization improves
o Data integrity, reusability, security and clarity of code
o Management and maintenance of code
o Performance and reliability of code.
PL/SQL provides a number of different structures that allow you to modularize code. By combining
these structures you can build entire applications.
Some of the modular structures provided by pl/sql include triggers, functions, procedures,packages.
Procedure:
A procedure is a named block of code that can accept parameters and perform one or more actions.
You can invoke a procedure as often as you want by using its name in the executable section of
other pl/sql code blocks.
When developing stored procedures, it is good to practice to
o Write code in an editor or word processor first and save it as a sql script file
o Load the file into a development tool, such as isql *plus
o Compile and store the procedure
o Then execute the procedure as needed
The syntax for creating procedure is currently displayed. It is comprised of a number of elements.
Functions:
A PL/SQL function is a named block that returns a value. In general, when you invoke a function, it
accepts an input value, carries out operations on it, and returns an output value.
If you want to use a function repeatedly, you can store it in the database as a schema object. It is
then referred to as a stored function.
In addition to storing a function in the database, you can create and store it in a client-side
application.
A PL/SQL function is similar to a procedure. However, there are a number of important difference
between them:
o Execution: You invoke a function as part of an expression. For example, you can call a function
as part of a PL/SQL expression or a sql statement. You invoke a procedure as a PL/SQL
statement – using an anonymous block or another procedure, for example.
o Returning Values: A function must always return a single value to the calling environment. A
procedure can pass zero or more values to and from the calling environment. It can return
values in its output parameters.
o The RETURN Keyword: To return a value, a function must include a RETURN clause in the
declarative section and at least one RETURN statement in the executable section. A procedure
does not have a RETURN clause in the declarative section, but it may contain a RETURN
statement in the executable section, even if it does not return a value.
Functions that are called by SQL statements should not contain OUT or IN OUT mode parameters. A
function that includes output parameters can be used in a PL/SQL procedure or block, but not in SQL
statements.
Like a procedure, a function includes a declarative section, an executable section, and an optional
exception-handling section.
Here is an example of a function called tax. In this case, it does not include an exception handling
section. The function returns the tax contribution of each employee that works in the department
with an ID number of 100 when you enter the employee’s salary.
Create or replace function tax(value in number) return number is
Begin
Return(value * 0.08);
End tax;
/
Select employee_id, last_name, salary, tax(salary) from employees where department_id = 100;
The above sql section calls and displays the values returned by the function for each employee. This
section shows that the function is called by a select statement, along with the employee_id,
last_name, and salary columns.
There are number of advantages associated with creating and calling stored pl/sql functions:
o Referencing: You can reference stored pl/sql functions from the same locations as sql
expressions. For example, you can insert a user-defined pl/sql function anywhere a built in sql
function, such as upper(), can be inserted.
o Calculations: You can create user-defined pl/sql functions to carry out calculations that are too
complex or awkward to implement with sql code. It also enables the creation of functions that
are otherwise unavailable with sql.
o Data Independence: Pl/sql functions increase the independence of user data by processing
complex data analysis in the oracle server instead of retrieving and processing the data within
the application.
o Efficient queries: You can make sql queries more efficient by including pl/sql functions in a
query rather than in the specific applications.
o Manipulation of new types of data: You can simplify the manipulation of new types of data –
latitude and longitude, for example – by encoding character strings and creating pl/sql
functions to perform calculations on the strings.
o Reusability and maintainability: Pl/sql functions are reusable and simple to maintain and
update. When a function is validated, it can be reused indefinitely in a number of different
applications. If your data processing requirements change, you only need to update the
function once to affect all of its instances.
You can include multiple RETURN statements in a function usually within an IF statement. Invoking
a function that contains multiple RETURN statements only executes one of them because after the
function returns a single value, the block is not processed any further.
To create a pl/sql function, you use the CREATE FUNCTION statement, which
o Declares a list of parameters
o Returns a single value
o Defines the actions to be carried out by the function
The syntax to create a function is below. It comprises a number of elements.
Create or replace function function_name Create or replace function get_sal
[(parameter1 [mode1] datatype1,…)] (id employees.employee_id%TYPE)
RETURN datatype IS|AS RETURN number IS
[local_variable_declarations; …] Sal employees.salary%TYPE := 0;
BEGIN BEGIN
--actions; Select salary into sal from employees
RETURN expression; Where employee_id = id;
END [function_name]; RETURN sal;
END get_sal;
Packages:
Overview of packages:
Packages are discrete units of pl/sql code that enable you to bundle related pl/sql types, variables,
data structures, exceptions, and subprograms together for convenience. They are usually used to
bundle related procedures and functions together.
For example, an employee_salaries package might contain procedures and functions, which
calculate wage rates, bonus schemes and tax data.
A package usually consists of two parts stored separately in the database – a specification, which is
the actual package, and a body, which contains all the functionality. The body section is optional.
A package itself cannot be parameterized or nested. Once you’ve written and compiled a package,
its contents can be shared by many applications.
When you reference a package for the first time, the entire package is loaded. Because of this no
time is lost or disk input/output (i/o) used up the next time you make a reference to the same
package.
Packages have several benefits. They are
o Enable applications to be enhanced and maintained more easily.
o Help improve the performance of an application
o Are not affected by application functionality issues.
Its considered best practice to always construct applications using packages. Even if you only want
to perform one procedure for a type of functionality, its likely that, in the future, you will want to
add another – if not more than one.
A package has two parts –
o Package Specification: The specification defines how a package is to be used. For example, it
may specify the programs that are to be used or what cursors may be opened. It is the
interface between executable code and your applications. It might include declarations for
public types, variables, constants, exceptions, cursors, or subprograms. It might also include
PRAGMAs, which are directives to the compiler.
o Package Body: The package body must contain the code required to implement
subprograms or other elements declared in the specification. The package body may also
define its own subprograms and other pl/sql constructs, such as types, variables, constants,
exceptions and cursors. It’s also possible to have no package body – for example, if the
specification doesn’t declare any subprograms, there may be no need for a body.
The specification and package body consist of public and private components.
Any components declared in the specification are considered public components. This means they
are available to any programs outside the package. In other words, the specification defines a public
application programming interface (API), which means, effectively, that its components can be
referenced by programs in an Oracle server environment that is external to the package, as well as
internal ones.
Subprograms and other elements in the package body are regarded as private components and can
be referenced as private components and can be referenced only by other constructs within the
same package body. Private components can reference the public components of any package.
Disadvantage in procedures:
Create or replace procedure customer_id(customer_id_in IN customer.customer_id%TYPE) IS
Name_and_id varchar2(20)
Begin
Select cust_last_name || ‘,’ || customer_id INTO name_and_id From customers
Where customer_id = customer_id_in;
End;
Suppose you want to query the customers table for last names of customers and customer IDs. You
want to display the results by merging the last name with the ID, separated by a comma – for
example “Andrews, 125”. This code fragment details how you would do this using a standalone
procedure, not a package.
The above code will return the results you want. However, because the length of the name_and_id
variable is hardcoded to 20 spaces, it could be problematic if the cust_last_name column were to be
expanded.
Another problem with this code is that the format of the output is restricted to “last name, ID”, and
you may require a different format.
Package Specification: Package Definition:
Create or replace package customer_pkg as Function name_and_id(
Subtype name_and_id_t IS varchare2(200); Last_in customer.cust_last_name%TYPE,
Id_in customer.customer_id%TYPE)
Function name_and_id( RETURN name_and_id_t
Last_in customer.cust_last_name%TYPE, IS
Id_in customer.customer_id%TYPE) Begin
RETURN name_and_id_t Return last_in || ‘,’ || id_n;
End;
Function name_and_id( Function name_and_id(
Customer_id_in IN customer.customer_id%TYPE) Customer_id_in IN customer.customer_id%TYPE)
Return name_and_id_t; Return name_and_id_t
End customer_pkg; IS
Retval name_and_id_t;
Begin
Select name_and_id(cust_last_name, customer_id) into retval
From customers where customer_id = customer_id_in;
Return retval;
End;
End customer pkg;
In order to overcome these problems, you should consider using a package. This involves writing
one definition of a data type, one representation of the formula, and one version of the query,
which can be reused as many times as you want.
First you create a specification with a new data type called name_and_id_t.
Then you declare a function called name_and_id that accepts a customers last name and if and
returns them. You write a second function, also called name_and_id, which accepts a primary key
for a customer and returns a las name and ID. You then end the package specification.
Having completed the package specification, you can then create the package body, which
implements the specification, to produce the same results as the previous standalone procedure.
Visibility of components:
The degree to which a component is available to other components and objects is referred to as its
visibility. The visibility of components depend on whether they are locally or globally declared, and a
components’s visibility affects how its used and referenced.
Package Specification(Public): Package Body(Private):
Variable_1; Variable_2
Subprogram_1; Subprogram_2 is
Begin….End;
Subprogram_1 is
Variable_3
Begn … End;
A locally defined component is visible within the structure in which its declared. Locally defined
components are found in the package body. For example, variables defined in a subprogram can be
referenced within that subprogram and are not visible to external components. In the displayed
example, the variable, varaiable_3, can be used in the subprogram_1.
Other local components, such as private package variables that are declared in a package body, can
be referenced by other components in the same package body and are not visible to any
subprograms or objects outside the package. In the displayed example, the variable – variable_2 –
can be used by the subprograms – subprogram_1 and subprogram_2 – within the package body but
not outside the package.
Globally declared components, found in the specification, are visible both internally and externally
to the package, such as in example:
o Variable_1: A public variable that is declared in a package specification can be referenced
and changed outside the package. In this example, variable_1 can be referenced externally.
o Subprogram_1: A package subprogram in the specification can be called by external
programs. In this example, subprogram_1 can be called from, say, another block of code
that is external to the package.
Creating a package specification:
All packages have a specification section and most packages have a body section. In order to
develop a particular package, you must decide what code to put into each section. You may also
include code to enable oracle to initialize the package.
There are some additional, general guidelines for developing packages. You should save two sql files
– one for the specification and one for the body – in case you need to modify one or the other, or
reuse the package with a different body.
Also, you should be aware that when you load your package, oracle stores the specification and
body separately. This means you don’t affect schema objects that call or reference a body
subprogram when you modify the implementation of that subprogram.
And, if you don’t declare any subprograms in the specification, a package body will not be required.
However, you must always have a package specification.
You can declare variables and constants of most data types in a package specification. Private
variables are declared in the body.
Data structure declarations are allowed, such as record or collection types, and you can also declare
procedure and function headers, as long as you complete the code for these in the body. You can
also include an explicit cursor and put the related query in the body – or you can have the entire
cursor in the specification.
CREATE [OR REPLACE] PACKAGE package_name IS|AS
Public type and variable declarations
Subprogram specifications
END [package_name];
To create a package specification, you use the Create Package command. You can include or replace
if you are overwriting an existing specification. You also use the IS or AS keywords to define it. You
must include a package name in the CREATE PACKAGE statement. This must be unique among
objects within the owing schema. You can also include the package name in the END statement but
this is optional.
You declare you public variables, constants, cursors, exceptions, user defined types, and subtypes in
the specification. You can also initialize a specification variable with a constant value or formula. This
enables oracle to initialize the package – otherwise, the variable is initializes as NULL by default.
In the subprogram specifications, you specify the public procedure or function declarations. You
include only the headers followed by a semicolon. The actual implementation is included in body.
Create or replace package bonus_pkg IS
Std_bonus Number := 0.10;
Procedure reset_bonus(new_bonus Number);
End bonus_pkg;
Creating a package body:
In the package body, you write all the code that’s necessary to complete the procedures declared in
the specification. If no procedures were declared in the specification, theres no need for a package
body.
You need a package body if
o The package specification contains a cursor declaration with a return clause.
o The package specification contains a procedure or function declaration.
o You want to execute code in the initialization section of the package body.
Here is the syntax of package body.
Create [or replace] package body package_name IS|AS
Private type and variable declarations
Subprogram bodies
[Begin initialization statements]
End [package_name];
You use the create package body statement to create a package body, and you can also use the or
replace statement if a package body of the same name already exists. You include the package
name, making sure it’s the same as in the specification, and you can include this name in the end
statement if you want. However, this is optional.
Public variables and other public components are declared in the specification, but private variables,
constants, cursors, exceptions, user defined types, and subtypes are declared in the package body.
Subprograms in the body implement private or public procedures or functions in full. The order of
implementation is important – if you want to reference a variable or subprogram in any component,
you must declare it first so you need to order your components appropriately. And, for convenience,
you may decide to define all private variables and subprograms before defining public subprograms.
You may include an optional block of initialization code that executes when the package is first
referenced.
Create a package body for the specification you created earlier.
Create or replace package body bonus_pkg is
Function validate(bonus number) return Boolean is max_bonus employees.bonus_pct%type;
Begin
Select max(bonus_pct) into max_bonus from employees;
Return (bonus between 0.0 and max_bonus);
End validate;
Procedure reset_bonus (new_bonus Number) is begin
If validate(new_bonus) then
Std_bonus := new_bonus;
Else raise_application_error(-20210, ‘Bad bonus’);
End If;
End reset_bonus;
Invoking package subprograms:
Once a package is loaded into the database and stored there, you may want to invoke its public or
private subprograms. You can do this directly from within the package.
You can also invoke a package’s subprograms from another program that is external to the package.
In this case, you can invoke public subprograms only, and you also need to indicate the package
name. You use the syntax package_name.subprogram.
Using a package name when invoking a subprogram from within the package is optional. Pl/sql will
automatically resolve the reference.
Suppose you have created a package, called bonus_pkg, containing a validate function. You want to
call this function from within a procedure, called reset_bonus, which you are developing within the
same package.
Create or replace package body bonus_pkg is
Procedure reset_bonus(new_bonus number) is
Begin
If validate(new_bonus) then
Std_bonus := new_bonus;
Else
End if;
End reset_bonus;
End bonus_pkg;
If a procedure, reset_bonus, is owned by a different user schema – say for the user, tonya chavis –
you can call this. You must prefix the qualified package procedure with the schema name, Chavis.
Execute chavis.bonus_pkg.reset_bonus(0.15)
Viewing and removing packages:
All the source code for pl/sql packages is stored in data dictionary tables if you need to maintain or
modify them. The code is available in the USER_SOURCE and ALL_SOURCE tables.
When a package is no longer required, you can use a sql statement to remove it. All packages have
two parts – a specification and a body. You have the option of removing the entire package.
Alternatively, you can remove just the package body, leaving the package specification.
To remove the entire package – both the package specification and the body – you use a particular
syntax: Drop package package_name;
You also use the drop statement when removing the package body.
Drop package body package_name;
Overloading subprograms:
The overloading feature in pl/sql enables you to develop two or more packaged subprograms with
the same name. You can use the same name for different subprograms provided their formal
parameters differ in number, order, or data type family. The overloading feature is very useful
because it allows the same operation to be applied to objects of different types.
Create or replace package overload_package IS
Procedure proc1(x number);
Procedure proc1(x varchar2, y number);
Procedure proc1(x varchar2);
End overload_package;
The overloading feature can be used with local subprograms, package subprograms, and type
methods, but not with standalone subprograms.
You should consider using overloading for a number of reasons like flexibility, user friendliness and
scalability.
There are certain cases when the overloading feature cant and shouldn’t be used. If you use the
overloading feature in any of these instances, a runtime error will be returned.
o You cannot overload two subprograms if their parameters differ only in the parameter
passing modes.
Procedure overloadme(p_theparameter in number);
Procedure overloadme(p_theparameter out number);
o You cannot overload two functions based on their return type only.
Fucntion overloadmetoo return date;
Fucntion overloadmetoo return number;
o The parameters of overloaded functions must differ by family type. In this example, the char
and varchar2 data types are in the same family type.
Procedure overloadchar(p_theparameter in char);
Procedure overloadchar(p_theparameter in varchar2);
The program compiler attempts to find a declaration that matches a call. It searches the current
scope first, and then, if necessary, searches in successive enclosing scopes. The compiler stops
searching if it finds one or more subprogram declarations in which the name matches the name of
the called subprogram.
For similarly named subprograms at the same level of scope, the compiler needs an exact match in
number, order, and data type between the actual and formal parameters.
Forward declaration in a pl/sql package:
In general, pl/sql is like other block structured languages and does not allow forward references.
You must declare an identifier before using it. For example, a subprogram must be declared before
you call it.
Coding standards often require that subprograms be kept in alphabetical sequence to make them
easy to find. In this code, for example, you may encounter problems where the calc_rating
procedure cannot be referenced because it has not yet been declared.
Create or replace package body forward_pkg is
Procedure award_bonus(….) is
Begin
Calc_rating(….); ---illegal reference
End;
Procedure calc_rating(…..) is
Begin ….. End;
End forward_pkg;
You can solve illegal reference problems by reversing the order of the two procedures. However,
this solution does not work if the coding rules require subprograms to be declared in alphabetical
order.
The solution in this case is to use forward declarations provided in pl/sql. A forward declaration
enables you to declare the heading of a subprogram – that is, the subprogram specification
terminated by a semicolon.
Procedure calc_rating(………); -- forward declaration.
Forward declarations help to
o Define subprograms in a logical or alphabetical order.
o Define mutually recursive subprograms, which are programs that call each other directly or
indirectly
o Group and logically organize subprograms in a package body
Functions of the PL/SQL wrapper:
The pl/sql wrapper is a standalone utility that converts pl/sql source code into portable object code.
It allows you to deliver pl/sql applications without exposing your source code, which may contain
proprietary algorithms and data structures.
The wrapper converts the readable source code into unreadable code. By hiding application
internals, it prevents misuse of your application.
In terms of practical applications, a wrapper might be used by a company to distribute any pl/sql
based software that it sells over the internet.
The distributed code may be executed as normal, but customers are unable to see the actual source
code. Its important to remember though that the wrapped code is usually much larger than the
source code from which it is generated.
Wrapped code, such as pl/sql stored programs, has several notable features, It
o Is platform independent
o Permits dynamic loading
o Permits dynamic binding
o Offers dependency checking
o Supports importing and exporting
The wrapper is an operating system executable called WRAP. To run the wrapper, you enter the
command at your operation system prompt using the syntax.
$ WRAP INAME = input_file_name [ONAME = output_file_name]
Elements in command line syntax to run the wrapper are
$ WRAP INAME = student.sql ONAME = student.plb
o The Iname argument is required
o The default extension for the input file is .sql, but u can use any extension.
o The oname argument is optional in the command line syntax.
o The default extension for the output file is .plb – which stands for pl/sql binary although the
output file is not really a binary file. You can specify any extension for the output file.
After the wrapper file is created, you execute the PLB file from isql*plus to compile and store the
wrapped version of the source code in the same way that you would execute sql script files.
$@ORACLE_HOME/wrap/example.plb
There is a difference between the original pl/sql source code in an input file and the wrapped code.
Original PL/SQL Wrapped PL/SQL
Create package banking is Create package banking
Min_bal := 100; Wrapped
No_funds Exception; 012abc436e…….
…
End banking;
When it is wrapped, an object type, package, or subprogram takes the form of header, followed by
the word wrapped, and then followed by the unreadable body.
In order to run the wrapper efficiently, it is recommended that you follow several guidelines in
specifying argument, spaces, the input file, case sensitivity, the output file, no spaces around INAME
and ONAME.
The input file can contain any combination of sql statements. However, the pl/sql wrapper wraps
only a distinct number of Create statements:
Type, type body, package, package body, function, procedure.
All other sql create statements are passed intact to the output file like table, trigger and index.
Other important guidelines that you should adhere to include only wrapping the package body and
not the package specification. This ensures that other developers have the information they need to
use the package without exposing its implementation.
The output file should not be edited because its contents are not readable and editing this file could
potentially render it invalid. To change a wrapped object, you need to modify the original source
code and wrap the code again.
If your input file contains syntactic errors, the pl/sql wrapper detects and reports them . However,
the wrapper cannot detect semantic errors because it does not resolve external references. For
example, the wrapper does not support an error if the table or view amp does not exist.
However, the pl/sql compiler resolves external references. Therefore semantic errors are reported
when the wrapper output file (.plb file) is compiled.
Wrapping the body and not the specification of a package or object type gives other developers the
information they need to use the package without exposing its implementation.
Triggers:
A trigger is a pl/sql block or procedure associated with a table, view, schema, or database. Triggers
execute implicitly whenever a particular event takes place.
There are two different types of triggers – application and database.
An application trigger fires whenever an event occurs within a particular application.
A database trigger fires whenever a data event, such as a DML event, or a system event, such as a
logon or shutdown, occurs on a schema or database. Triggers represent an important element of a
well designed application built on the oracle database.
Database triggers perform a number of key functions:
o Validation on alterations to tables.
o Automatic database maintenance
o Setting rules for acceptable database administration
A programmer designs triggers to perform related actions and to centralize global actions. You can
use database triggers
o As alternatives to features provided by the oracle server.
o If your requirements are more complex or more simple than those provided by the oracle
server.
o If your requirements are not provided by the oracle server at all
The syntax for creating a trigger is
Create [or replace] trigger trigger_name
{Before | After |Instead of } triggering_event
[referencing_clause]
[When trigger_condition]
[For each row]
Trigger_body;
The trigger_name element in the syntax refers to the name of the trigger.
The triggering_event element in the syntax specifies the event that fires the trigger. This can even
include a specific table or view.
The referencing_clause element in the syntax is used to refer to the data in the row currently being
modified by a different name.
The trigger_condition element in the syntax in the When clause, if present, is evaluated first, and the
body of the trigger is executed only when this condition evaluates to True.
Suppose you are updating your employee records on a regular basis. You could use a trigger like the
below example, which inserts a record into the employees_history table every time there is an
update on a row in the employees table.
Create or replace trigger emphisttrigger
Before update on employees
For each row
Begin
Insert into employees_history values (:new.employee_id, :new.first_name, :new.last_name,
:new.email, sysdate);
End emphisttrigger;
Enhancements provided by triggers:
You can develop database triggers to augment features that cannot otherwise be executed by the
oracle server.
The following features of triggers are useful in business scenarios:
Security Auditing Referential integrity
Table replication Derived data Event logging