Professional Documents
Culture Documents
PLSQL 100 Rs
PLSQL 100 Rs
PLSQL 100 Rs
Version 2.0
Preface
I hope you will find this book very much beneficial. Your
suggestions are most welcome on.
Email: - rahul@focustraining.in
- Rahul V. Giri
Oracle first introduced Procedural Language/Structured Query Language (PL/SQL) in version 6.0 of its
relational database management system (RDBMS). As its RDBMS evolved, Oracle made
developmental changes to the PL/SQL language by introducing new features and enhancing existing
features. Oracle9i, the version of PL/SQL is PL/SQL 9.2 or 9.0 depending on whether it is Oracle9i
Release 2 (9.2.x) or Oracle9i Release 1 (9.0.x).
PL/SQL is a block-structured language. That is, the basic units (procedures, functions, and anonymous
blocks) that make up a PL/SQL program are logical blocks, which can contain any number of nested
sub-blocks. Typically, each logical block corresponds to a problem or sub problem to be solved. Thus,
PL/SQL supports the divide-and-conquer approach to problem solving called stepwise refinement
Anonymous Block
PL/SQL makes it easy to detect and handle errors. When an error occurs, PL/SQL raises an exception.
Normal execution stops and control transfers to the exception-handling part of the PL/SQL block. You
do not have to check every operation to ensure that it succeeded, as in a C program.
A PL/SQL subprogram is a named PL/SQL block that can be invoked repeatedly. If the
subprogram has parameters, their values can differ for each invocation. PL/SQL has two types of
subprograms, procedures and functions. A function returns a result.
Syntax of Procedure:
CREATE [OR REPLACE] PROCEDURE <procedure_name>
[ (parameter1 [mode] datatype1,
parameter2 [mode] datatype2,....) ]
IS | AS
[EXCEPTION
exception_section]
END [procedure_name];
Packages
A package is a schema object that groups logically related PL/SQL types, variables, constants,
subprograms, cursors, and exceptions. A package is compiled and stored in the database, where
many applications can share its contents. You can think of a package as an application.
Triggers
A trigger is a named PL/SQL unit that is stored in the database and run in response to an event
that occurs in the database. You can specify the event, whether the trigger fires before or after
the event, and whether the trigger runs for each event or for each row affected by the event.
For example, you can create a trigger that runs every time an INSERT statement affects the
EMPLOYEES table.
Input and Output (PL/SQL I/O-Processing Packages)
Most PL/SQL input and output (I/O) is done with SQL statements that store data in database
tables or query those tables. For information about SQL statements, see Oracle Database SQL
Language Reference. All other PL/SQL I/O is done with PL/SQL packages that Oracle Database
supplies.
Topics
Cursors
Composite Variables
%ROWTYPE Attribute
%TYPE Attribute
Abstract Data Types
Every constant, variable, and parameter has a data type (or type), which specifies a storage format,
constraints, and valid range of values. PL/SQL provides a variety of predefined data types. For
instance, you can choose from integer, floating point, character, Boolean, date, collection, reference,
and LOB types. In addition, PL/SQL lets you define your own subtypes.
BINARY_INTEGER
You use the BINARY_INTEGER data type to store signed integers. Its magnitude range is -2**31 ..
2**31.NUMBER you use the NUMBER data type to store fixed-point or floating-point numbers. Its
magnitude range is 1E-130 .. 10E125. You can specify precision, which is the total number of digits,
and scale, which is the number of digits to the right of the decimal point. The syntax follows:
NUMBER
To declare integers, which have no decimal point, use this form:
NUMBER (precision)
Use the subtypes DEC, DECIMAL, and NUMERIC to declare fixed-point numbers with a maximum
precision of 38 decimal digits. Use the subtypes DOUBLE PRECISION and FLOAT to declare floating-
point numbers with a maximum precision of 126 binary digits, which is roughly equivalent to 38
decimal digits. Or, use the subtype REAL to declare floating-point numbers with a maximum
precision of 63 nary digits, which is roughly equivalent to 18 decimal digits. Use the subtypes
INTEGER, INT, and SMALLINT to declare integers with a maximum
precision of 38 decimal digits.
PLS_INTEGER
You use the PLS_INTEGER data type to store signed integers. Its magnitude range is -2**31 .. 2**31.
Although PLS_INTEGER and BINARY_INTEGER have the same magnitude range, they are not fully
compatible. When a PLS_INTEGER calculation overflows, anexception is raised. However, when a
BINARY_INTEGER calculation overflows, noexception is raised if the result is assigned to a NUMBER
variable. Because of this small semantic difference, you might want to continue using
BINARY_INTEGER in old applications for compatibility. In new applications, always use PLS_INTEGER
for better performance.
CHAR
You use the CHAR data type to store fixed-length character data. The CHAR data type takes an
optional parameter that lets you specify a maximum size up to 32767 bytes.
VARCHAR2
You use the VARCHAR2 data type to store variable-length character data. The VARCHAR2 data type
takes a required parameter that specifies a maximum size up to 32767 bytes. The syntax follows:
If one value in a comparison has data type VARCHAR2 and the other value has data type CHAR, non-
blank-padding semantics are used. But, remember, when you assign a character value to a CHAR
variable, if the value is shorter than the declared length of the variable, PL/SQL blank-pads the value
to the declared length. So, given the declarations
ROWID
Internally, every database table has a ROWID pseudo column, which stores binary values called
rowdies. Each rowid represents the storage address of a row. A physical rowid identifies a row in an
ordinary table. For example, in SQL*Plus (which implicitly converts rowids into character strings), the
query
SQL> SELECT row_id , ename FROM emp WHERE empno = 7788;
ROWIDE NAME
------------------ ----------
AAAAqcAABAAADFNAAH SCOTT
DATE
You use the DATE datatype to store fixed-length datetimes, which include the time of day in seconds
since midnight. The date portion defaults to the first day of the current month; the time portion
defaults to midnight. The date function SYSDATE returns the current date and time.
You can add and subtract dates. In arithmetic expressions, PL/SQL interprets integer literals as days.
For instance, TIMESTAMP
The datatype TIMESTAMP, which extends the datatype DATE, stores the year, month,day, hour,
minute, and second.The syntax is:
TIMESTAMP[(precision)]
Where the optional parameter precision specifies the number of digits in the fractional part of the
seconds field. You cannot use a symbolic constant or variable to specify the precision; you must use
an integer literal in the range 0 .. 9. The default is 6. In the following example, you declare a variable
of type TIMESTAMP, and then assign a literal value to it:
DECLARE
checkout TIMESTAMP(3);
BEGIN
checkout := '1999-06-22 07:48:53.275';
...
END;
/
“In this example, the fractional part of the seconds field is 0.275.”
BINARY INTEGER:-
Base type for integer between -2,147,483,647 and 2,147,483,647
PLS_INTEGER :-
Base type for signed integers between -2,147,483,647 and 2,147,483,647 PLS_INTEGER values
require less storage and are faster than NUMBER and BINARY_INTEGER values
BOOLEAN:-
Base type that stores one of three possible values used for logical calculations: TRUE, FALSE, NULL
This is the first program in plsql to print “Hello world”.
create or replace procedure sp1
as
-- First Program of Plsql
-- This Program Prints
-- Hello World on the Screen
begin
dbms_output.put_line('Hello World');
-- [dbms_output is a PL-SQL Package and put_line is their Package
member which is user for print Character or string ]
end;
/
OUTPUT:
SQL> @sp1.sql
Procedure created.
No errors.
begin
v_myname := ‘Nagnath’;
dbms_output.put_line('My Name is '||v_myname);
dbms_output.put_line('My Age is '||v_myage);
end;
/
OUTPUT:
SQL> @sp2.sql
Procedure created.
No errors.
SQL> exec sp2
My Name is Nagnath
My Age is 21
begin
dbms_output.put_line('Name Entered By User: '||l_name);
dbms_output.put_line('Age Entered By User: '||l_age);
end;
/
show errors
Set serveroutput on
OUTPUT:
OUTPUT
SQL> @sp4.sql
OUTPUT:
SQL> @sp5
Procedure created.
No errors.
As
l_no number := 600;
l_msg varchar2(20) := 'Global Variable';
Begin
<<Inner_Block1>>
Declare
l_no Number := 1;
l_msg varchar2(20) := 'Local variable';
Begin
l_no := l_no +1;
dbms_output.put_line('In Inner Block1');
dbms_output.put_line(l_no);
dbms_output.put_line(l_msg);
End;
<<Inner_Block2>>
Declare
l_no number :=100;
Begin
dbms_output.put_line('In Inner Block2');
dbms_output.put_line(l_no);
dbms_output.put_line(sp16.l_msg);
End;
dbms_output.put_line('In Main');
dbms_output.put_line(l_no);
OUTPUT:
SQL> @sp6.sql
Procedure created.
No errors.
OUTPUT:
create table test(test_id number,test_name varchar2(10));
Table created.
SQL> @sp7.sql
Procedure created.
No errors.
SQL> exec sp17
PL/SQL procedure successfully completed.
SQL> select * from test;
TEST_ID TEST_NAME
------- ----------------
1 sql
2. Display employee name , salary, job_id,city,region_id and pass the department number using
parameter procedure?
3. Display employee name , salary, job whos employee_id is 100 (using %type veriable)?
The selection structure tests a condition, and then executes one sequence of statements instead of
another, depending on whether the condition is true or false. A condition is any variable or
expression that returns a Boolean value (TRUE or FALSE). The iteration structure executes a sequence
of statements repeatedly as long as a condition holds true. The sequence structure simply executes a
sequence of statements in the order in which they occur.
IF-THEN Statement
The simplest form of IF statement associates a condition with a sequence of statements enclosed by
the keywords THEN and END IF (not ENDIF), as follows:
IF condition THEN
sequence_of_statements
END IF;
The sequence of statements is executed only if the condition is true. If the condition is false or null,
the IF statement does nothing . You might want to place brief IF statements on a single line, as in
IF-THEN-ELSE Statement
The second form of IF statement adds the keyword ELSE followed by an alternative sequence of
statements, as follows:
IF condition THEN
sequence_of_statements1
ELSE
sequence_of_statements2
END IF;
The sequence of statements in the ELSE c lause is executed only if the condition is falseor null.
Thus, the ELSE clause ensures that a sequence of statements is executed. In the following example,
the first UPDATE statement is executed when the condition is true, but the second UPDATE
statement is executed when the condition is false or null
Syntax:-
IF condition THEN
sequence_of_statements1
The sequence of statements is executed only if the condition is true. If the condition is false or null,
the IF statement does nothing. In either case, control passes to the next statement. An example
follows:
As
l_hire_date employees.hire_date%type;
l_salary employees.salary%type;
l_years_of_service number := 0;
l_new_salary number := 0;
begin
select hire_date, salary
into l_hire_date, l_salary
from employees
update employees
set salary = l_new_salary
where employee_id = p_employee_id;
commit;
end;
/
Show error
Set serveroutput on
OUTPUT:
SQL> @sp8.sql
Procedure created.
No errors.
SQL> select salary from employees where employee_id=101;
SALARY
----------
17000
SQL> exec sp8(101);
Like the IF statement, the CASE statement selects one sequence of statements to execute. However,
to select the sequence, the CASE statement uses a selector rather than multiple Boolean expressions.
To compare the IF and CASE statements, consider the following code that outputs descriptions of
school grades:
CASE selector
WHEN expression1 THEN result1
WHEN expression2 THEN result2
...
WHEN expressionN THEN resultN
[ELSE resultN+1;]
END;
--A CASE expression selects a result and returns it
begin
l_appraisal := CASE p_grade
WHEN 'A' THEN 'Excellent'
WHEN 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good'
ELSE 'No such grade'
OUTPUT:
SQL> @sp9.sql
Procedure created.
No errors.
The CASE statement is more readable and more efficient. So, when possible, rewrite lengthy IF-THEN-
ELSIF statements as CASE statements.Iterative Control: LOOP and EXIT Statements LOOP statements
let you execute a sequence of statements multiple times. There are three forms of LOOP statements:
LOOP, WHILE-LOOP, and FOR-LOOP.
3.3.1 LOOP
The simplest form of LOOP statement is the basic (or infinite) loop, which encloses a sequence of
statements between the keywords LOOP and END LOOP, as follows:
LOOP
sequence_of_statements
END LOOP;
With each iteration of the loop, the sequence of statements is executed, then control resumes at the
top of the loop. If further processing is undesirable or impossible, you can use an EXIT statement to
complete the loop.
LOOP
IF credit_rating < 3 THEN
EXIT;
-- exit loop immediately
END IF;
END LOOP;
-- control resumes here
*Remember, the EXIT statement must be placed inside a loop. To complete a PL/SQL block before
its normal end is reached, you can use the RETURN statement.*
3.3.3 EXIT-WHEN
The EXIT-WHEN statement lets a loop complete conditionally. When the EXIT statement is
encountered, the condition in the WHEN clause is evaluated. If the cond -ition is true, the loop
completes and control passes to the next statement after the loop. An example follows:
LOOP
FETCH c1 INTO ...
EXIT WHEN c1%NOTFOUND;
-- exit loop if condition is true
...
END LOOP;
CLOSE c1;
Until the condition is true, the loop cannot complete. So, a statement inside the loop must change
the value of the condition. In the last example, if the FETCH statement returns a row, the condition is
false. When the FETCH statement fails to return a row, the condition is true, the loop completes, and
control passes to the CLOSE statement.
Programer can use exit condition to terminate the loop An example follows:
create or replace procedure sp10 ( p_loop_counter in number)
As
i number;
Begin
i := 1;
loop
dbms_output.put_line(to_char(i) );
exit when i >= p_loop_counter;
i := i +1;
end loop;
End;
/
show errors
OUTPUT
SQL> @sp10.sql
Procedure created.
No errors.
SQL> exec sp10(5);
1
2
3
4
5
PL/SQL procedure successfully completed.
The WHILE-LOOP statement associates a condition with a sequence of statements enclosed by the
keywords LOOP and END LOOP, as follows:
Before each iteration of the loop, the condition is evaluated. If the condition is true, the sequence of
statements is executed, then control resumes at the top of the loop. If the condition is false or null,
the loop is bypassed and control passes to the next statement. An example follows:
create or replace procedure sp11 ( p_loop_counter in number)
as
i number;
begin
i := 1;
while i<= p_loop_counter
loop
dbms_output.put_line(to_char(i) );
i := i + 1;
end loop;
end;
/
show errors
Use the WHILE loop if the condition has to be evaluated at the start of each iteration.
While loop performs repetative actions until controling condition is no longer True.
The condition is checked at start of each transaction.
3.3.6 FOR-LOOP
Whereas the number of iterations through a WHILE loop is unknown until the loopcompletes, the
number of iterations through a FOR loop is known before the loop is entered. FOR loops iterate over
a specified range of integers. The range is part of an iteration scheme, which is enclosed by the
keywords FOR and LOOPS. A double dot ( .. ) serves as the range operator. The syntax follows:
An example follows:
OUTPUT
SQL> @sp12.sql
Procedure created.
No errors.
Dynamic Ranges
PL/SQL lets you determine the loop range dynamically at run time, as the following example shows:
The value of emp_count is unknown at compile time; the SELECT statement returns the value at run
time. What happens if the lower bound of a loop range evaluates to a larger integer than the upper
-- limit becomes 1
FOR i IN 2..limit LOOP
sequence_of_statements -- executes zero times
END LOOP;
-- control passes here
Scope Rules
The loop counter is defined only within the loop. You cannot reference it outside the loop. After the
loop is exited, the loop counter is undefined, as the following example shows:
3. Display employee with the bonous , Bonus is 15% of commission drawn by the employee if the
employee does not earn any commission then display message ‘ Does not earn any commission’.
Otherwise add Bonus to the salary of the mployee and display it on the screen.The block should
accept an input for the employe number ?
1) Records
2) %rowtype
3) Index by table
4.1 Records
Composite Data type Records stores more than one data type under single record .
4.2 %rowtype
%rowtype variable is used to store all column data types in single variable
begin
select *
into emp_record
from employees
where employee_id = 100;
dbms_output.put_line('Name: '||emp_record.last_name);
dbms_output.put_line('Department Id: '||
emp_record.department_id);
end;
OUTPUT:
SQL> @sp14.sql
Procedure created.
No errors.
OUTPUT
SQL> @sp15.sql
Procedure created.
No errors.
2. Write pl/sql block to print employee full name, salary and manager full name when
employee_id is passed in. The out should be as follows: (By using %row type)
Cursor is a mechanism by which you can assign a name to a "select statement" and manipulate the
information within that SQL statement. PL/SQL uses two types of cursors: implicit and explicit.
PL/SQL declares a cursor implicitly for all SQL data manipulation statements, including queries that
return only one row. However, for queries that return more than one row, you must declare an
explicit cursor, use a cursorFOR loop, or use the BULK COLLECT clause.
While dealing with cursors, you may need to determine the status of your cursor. The following is a
list of the cursor attributes that you can use. You have already learned that you can include SQL
statements that return a single row in PL/SQL block. The data retrieved by the SQL statement should
be held in variables using the INTO clause.
The Oracle server allocates a private memory area called the context area for processing SQL
Statements. Information required for processing and information retrieved after processing is 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. 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:
1)SQL%ROWCOUNT
2)SQL%FOUND
3)SQL%NOTFOUND
%NOTFOUND Attribute:
%NOTFOUND is the logical opposite of %FOUND. %NOTFOUND yields TRUE if an INSERT, UPDATE, or
DELETE statement affected no rows, or a SELECT INTO statement returned no rows. Otherwise,
%NOTFOUND yields FALSE.
For example, you might declare cursors named c1 and c2, as follows:
DECLARE
CURSOR c1 IS SELECT empno, ename, job, sal FROM emp
WHERE sal > 2000;
CURSOR c2 RETURN dept%ROWTYPE IS
SELECT * FROM dept WHERE deptno = 10;
DECLARE
CURSOR c1 IS SELECT employee_id, job_id FROM employees WHERE
salary < 3000;
...
BEGIN
OPEN c1;
...
END;
Rows in the result set are not retrieved when the OPEN statement is executed. Rather, the FETCH
statement retrieves the rows.
*Note: Although it is possible to terminate the PL/SQL block without closing cursors, you should
make it a habit to close any cursor that you declared explicitly to free up resources.
Example2: Process the rows of the active set by fetching values into a PL/SQL record.
SQL>set serveroutput on
SQL>declare
OUTPUT:
SQL> @sp16.sql
Procedure created.
No errors.
SQL> exec sp16
Name: Hartstein
Salary: 13000
Name: Fay
Salary: 6000
OUTPUT:
SQL> @sp17.sql
Syntax:
select ....
from ....
for update [of column_reference] [NOWAIT | WAIT n];
rec_c1 c1%rowtype;
l_new_sal number;
Begin
dbms_output.put_line(rpad('Employee',15)|| rpad('Old
Salary',15)|| rpad('New Salary',15));
open c1;
loop
fetch c1 into rec_c1;
exit when c1%notfound;
if rec_c1.salary < 7000 then
l_new_sal:= rec_c1.salary * 1.25;
Example:
create or replace procedure sp18
as
cursor c1 is
select employee_id,salary
from employees
where department_id = 20
for update of salary nowait;
l_new_sal number; rec_c1
c1%rowtype;
begin
OUTPUT:
SQL> @sp18.sql
Procedure created.
No errors.
Department id employee_id
------------------------ --------------------------
10 3
20 2
30 1
40 6
------------------------------------------------------------------
Total : 11
2. Write a program that gives all employee in department 10 a 10% increase, Display a message
“How many Employees where evarded the increase?
3. Write PL/SQl Block that copies all departments to a table called dept_copy?
(It use while loop and Display how many rows were copied)).
Run-time errors arise from design faults, coding mistakes, hardware failures, and many other
sources. Although you cannot anticipate all possible errors, you can plan to handle certain kinds of
errors meaningful to your PL/SQL program. With PL/SQL, a mechanism called EXCEPTION HANDLING
lets you "bulletproof" your program so that it can continue operating in the presence of errors. An
exception is an error in PL/SQL that is raised during the execution of a block.
A block always terminates when PL/SQL raises an exception, but you can specify and exception
handler to perform final actions before the block ends.
There is no syntax error in above code, which means you must be able to successfully execute the
anonymous block.
The select statement in the block retrieves the last_name of John. You see the following output when
you execute the code:
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 4
The ORA-06512 error itself does not indicate the actual error. It normally indicates the line number at
which the oracle PL/SQL code has caused an error.
There will be another main error occurred in your process and that error happened in the line
number as mentioned in ORA-06512 message description.
Like for example, the first line of the error message like ORA-01422 may indicate the actual error that
occurred, while the second line of the error message (ie: ORA-06512) indicates that the error
occurred at which line number of the PLSQL code.
The code does not work as expected. You expected the select statement to retrieve only one row;
however, it retrieves multiple rows.
Such errors that occur at run time are called exceptions. When an exception occurs, the PL/SQL block
is terminated.
You can handle such exceptions in your PL/SQL block.
For exception handling, you include another optional section called the exception section. This
section begins with the keyword EXCEPTION.
If present, this is last section in a PL/SQL block.
The code is rewritten to handle the exception that occurred. The output of the code is:
Your select statement retrieved multiple rows. Consider using a
cursor.
PL/SQL prcedure successfully completed.
Error processing is not clearly separated from normal processing; nor is it robust. If you neglect to
code a check, the error goes undetected and is likely to cause other, seemingly unrelated errors.
With exceptions, you can handle errors conveniently without the need to code multiple checks.
Exceptions improve readability by letting you isolate error-handling routines. If the exception is ever
raised in that block (or any sub-block), you can be sure it will be handled.
Non-predefined exceptions are similar to predefined exceptions; however, they are not defined as
PL/SQL exceptions in the Oracle server.
They are standard Oracle errors. You create exceptions with standared oracle errors by using the
PRAGMA EXCEPTION_INIT function. Such exceptions are called non-predefined exceptions.
You can trap a non-predefined Oracle server error by declaraing it first. The declared exception is
raised implicitly.
In PL/SQL, PRAGMA EXCEPTION_INIT tells the complier to associate an exception name with an
Oracle error number. That enables you to refer to any internal exception by name and to write a
specific handler for it.
Step 2:
SQL> begin
2 insert into departments (department_id, department_name)
values(280,null);
3 end;
4 /
OUTPUT:
Begin
*
ERROR at line 1:
ORA-01400: cannot insert NULL into
("VIVEK"."DEPARTMENTS"."DEPARTMENT_NAME")
ORA-06512: at line 2
Step 3:
SQL> set serveroutput on
SQL> declare
insert_excep EXCEPTION; -- declare the name of exception
PRAGMA EXCEPTION_INIT(insert_excep,-01400); --associate the
declared exception with the standard oracle server error number
begin
insert into departments(department_id, department_name)
OUTPUT:
Insert operation failed
ORA-01400: cannot insert NULL into
("VIVEK"."DEPARTMENTS"."DEPARTMENT_NAME")
DECLARE
past_due EXCEPTION;
Example:
SQL> declare
2 invalid_department EXCEPTION; --declare the name of the
exception
3 begin
4 update deptcopy
5 set department_name='Sports'
6 where department_id=999;
7 if sql%notfound then
8 raise invalid_department; --raise the exception explicitly
9 end if;
10 exception
11 when invalid_department then -- handle the raised exception
12 dbms_output.put_line('No such department id');
13 end;
14 /
OUTPUT:
No such department id
where exception_name is the name of a previously declared exception and the number is a negative
value corresponding to an ORA- error number. The pragma must appear somewhere after the
exception declaration in the same declarative section, as shown in the following example:
DECLARE
deadlock_detected EXCEPTION;
PRAGMA EXCEPTION_INIT(deadlock_detected, -60);
BEGIN
-- Some operation that causes an ORA-00060 error
EXCEPTION
WHEN deadlock_detected THEN
--handle the error
END;
RAISE_APPLICATION_ERROR()
RAISE_APPLICATION_ERROR is a built-in procedure in oracle which is used to display the user-defined
error messages along with the error number whose range is in between -20000 and -20999.
Whenever a message is displayed using RAISE_APPLICATION_ERROR, all previous transactions which
are not committed within the PL/SQL Block are rolled back automatically (i.e. change due to INSERT,
UPDATE, or DELETE statements).
RAISE_APPLICATION_ERROR raises an exception but does not handle it.
RAISE_APPLICATION_ERROR is used for the following reasons,
a) to create a unique id for an user-defined exception.
b) to make the user-defined exception look like an Oracle error.
Focus Trainig Services, Pune Page 70
The General Syntax to use this procedure is:
RAISE_APPLICATION_ERROR (error_number, error_message);
example:
SQL> begin
2 update deptcopy
3 set department_name='Sports'
4 where department_id=999;
5 if sql%notfound then
6 raise_application_error(-20145,'No such department id');
7 end if;
8 end;
9 /
OUTPUT:
begin
ERROR at line 1:
ORA-20145: No such department id
ORA-06512: at line 6
OUTPUT:
no data found exception raised
1. Can the PL/SQL block process more than one exception at a time?
2. _________ function is used to get error message of the most recent error.
3. How do you associate an Oracle error with a user-defined error.
4. When UPDATE command could not update any rows then which of the following will happen?
a.NO_DATA_FOUND exception occurs
b.INVALID_UPDATE exception occurs
c.No exception is raised
5. When an exception is not handled in the current block
a. It results in error and terminates the block
b. It is propagated to outer block
c. It is ignored.
Anonymous blocks are unnamed executable PL/SQL blocks. Because they are unnamed they can be
neither use nor stored for later use.Subprograms are named PL/SQL blocks that can take parameters
and be invoked.PL/SQL has two types of subprograms calledProcedures and functions are named
PL/SQL blocks. They are also known as subprograms. These subprograms are compiled and stored in
the database.The block structure of the subprograms is similar to the structure of anonymous blocks.
A stored subprogram is a named PL/SQL block that's stored in the database. PL/SQL 11g/12c supports
three types of stored subprograms:
Procedures
Functions
Packages
[EXCEPTION
exception_section]
END [procedure_name];
IN
An IN parameter passes a constant value from the calling environment into the procedure. The IN
mode is the default if no mode is specified.IN parameters are passed as read-only values from the
calling environment into the procedure. Attempts to change the value of an IN parameter in called
subprogram result in compile-time error.
OUT
The OUT parameter passes a value from procedure to the calling environment. The OUT parameter
can be assigned values only in the body of the procedure in which they are declared. Make sure that
the data type for the actual parameter variables used to retrieve values from OUT parameters has a
size sufficient to hold the data values being returned.
IN OUT
An IN OUT parameter passes a value from the calling environment to the procedure and a possibly
different value from the procedure back to the calling environment using the same parameter.
Compile Of file
SQL> @<FILE_NAME>
Step2:-
declare
emp_name empcopy.last_name%type;
emp_sal empcopy.salary%type;
begin
query_emp(171,emp_name,emp_sal); --calling the procedure
dbms_output.put_line(emp_name||' '||emp_sal);
end;
/
Show errors
Set serveroutput ON
Step2:
SQL> @ sp21
You have created database object
Procedure created.
OUTPUT:
The City Name :- Canada
PL/SQL procedure successfully completed.
Example:
Create or replace procedure sp22(did number)
as
dname varchar2(40);
begin
select department_name into dname from departments where
department_id=did;
dbms_output.put_line(dname);
end;
/
SQL> @ sp22
passing by combination
execute sp23('Transport',locid=>1700,mgrid=>100);
Step2:
OUTPUT:
SQL> execute sp24;
------OR------
SQL> execute sp24('Testing',1700);
------OR------
SQL>execute sp24(locid=>1900);
Example:
SQL> SELECT text
FROM user_source
WHERE name='RAISE_SALARY' and type='PROCEDURE'
ORDER BY line;
Example:
SQL> DROP PROCEDURE raise_salary;
RETURN expression;}
[EXCEPTION
exception_section]
END [function_name];
/
Example:
As
sal number;
Begin
select salary into sal
from employees
where employee_id=id;
return sal;
End;
/
execute dbms_output.put_line(get_sal(108));
Example:
SQL> DROP FUNCTION raise_salary;
The package specification, which declares the public items that can be referenced from outside the
package. You can think of the package specification as the application programming interface (API).
The package body defines its own subprograms and must fully implement subprograms declared in
the specification part. The package may also define PL/SQL constructs, such as types, variables,
constants, exceptions and cursors.
Public components are declared in the package specification. The specification defines a public
application programming interface for users of package features and functionality- that is, public
components can be referenced from any oracle server environment that is external to the package.
Private components are placed in the package body and can be referenced only by other constructs
within the same package body.
A package specification can exist without a package body- that is when the package specification
does not declare subprograms, a body is not required. However, a package body can not exist
without a package specification.
Note: The package specification should contain procedure and function headings terminated by a
semicolon, without the IS (or AS) keyword and its PL/SQL block.
The implementation of procedure or function that is declared in a package specification is done in
the package body.
Example:
create or replace package calculation
is
procedure addition(a number, b number);
procedure substraction(a number, b number);
procedure multiplication(a number, b number);
procedure division(a number, b number);
end calculation;
/
Specify the OR REPLACE option to overwrite an existing package body. Define the subprograms in an
appropriate order. The basic principle is that you must declare a variable or subprogram before it can
be referenced by other
components in the same package body. It is common to see all private variables and subprograms
defined first and the public subprograms defined last in the package body.
Complete the implementation for all procedures or functions declared in the package specification
within the package body.
Example:
create or replace package body calculation
as
procedure addition(a number, b number)
as
begin
dbms_output.put_line('the addition:='||(a+b));
end;
OUTPUT:
SQL> @calculation.sql
Package body created.
SQL> execute calculation.addition(5,8); --calling addition procedure
of package calculation
Modularity and ease of maintenance: You encapsulate logically related pragramming structures in
named module. Each package is easy to understand and the interface between packages is simple,
clear and well defined.
Hiding information: You decide which constructs are public (visible and accessible) and which are
private(hidden and inaccessible). Declarations in the package specification are visible and accessible
to applications. The package body hides the definition of private constructs.
Better performance: When you call a packaged subprogram the first time, the entire package is
loaded into memory. Later calls to related subprograms in the package therefore require no further
disk I/O.
Overloading: With packages, you can overload procedures and functions, which means you can
create multiple subprograms with the same name in the same package, each taking parameters of
different number or data type.
You can remove only package body and retain the package specification using following syntax:
DROP PACKAGE BODY package_name;
Example:
Step1:
SQL>create table emp(empno NUMBER,
empname VARCHAR2(20),
jobid VARCHAR2(20),
hdate DATE,
sal NUMBER,
comm NUMBER);
SQL>create sequence empno_seq;
SQL>create table salgrade(grade char, losal number, hisal number);
Step2:
CREATE OR REPLACE PACKAGE emp_actions
AS
/* Declare externally callable subprograms. */
END emp_actions;
Step3:
CREATE OR REPLACE PACKAGE BODY emp_actions
AS
PROCEDURE hire_employee (ename VARCHAR2, job VARCHAR2, esal
NUMBER, comm NUMBER)
AS
new_empno NUMBER;
BEGIN
SELECT empno_seq.NEXTVAL INTO new_empno FROM dual;
INSERT INTO emp VALUES (new_empno, ename, job,SYSDATE,
esal, comm);
DBMS_OUTPUT.PUT_LINE('employee inserted successfully');
END hire_employee;
BEGIN
DELETE FROM emp WHERE empno = emp_id;
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('employee '||emp_id||' deleted
successfully');
ELSE
DBMS_OUTPUT.PUT_LINE('invalid employee');
END IF;
END fire_employee;
/* Define local function, available only inside package. */
FUNCTION sal_ok (rank CHAR, salary NUMBER)
RETURN BOOLEAN
AS
min_sal NUMBER;
max_sal NUMBER;
BEGIN
SELECT losal, hisal INTO min_sal, max_sal
FROM salgrade
WHERE grade = upper(rank);
RETURN (salary >= min_sal) AND (salary <= max_sal);
END sal_ok;
PROCEDURE raise_salary (emp_id NUMBER, grade CHAR, amount
NUMBER)
AS
salary NUMBER;
BEGIN
SELECT sal INTO salary
FROM emp
WHERE empno = emp_id;
IF sal_ok(grade, salary + amount) THEN
UPDATE emp
SET sal = sal + amount
WHERE empno = emp_id;
DBMS_OUTPUT.PUT_LINE('salary of employee'||emp_id||'
Note:- Overloading can be done with package subprograms but not with stad-alone subprograms.
Step1:
CREATE OR REPLACE PACKAGE emp_actions AS
/* Declare externally callable subprograms. */
PROCEDURE hire_fire_employee (ename VARCHAR2, job VARCHAR2,
esal NUMBER, comm NUMBER);
PROCEDURE hire_fire_employee (emp_id NUMBER);
PROCEDURE raise_salary (emp_id NUMBER, grade CHAR, amount
NUMBER);
END emp_actions;
Step2:
CREATE OR REPLACE PACKAGE BODY emp_actions
AS
PROCEDURE hire_fire_employee (ename VARCHAR2,job VARCHAR2,
esal NUMBER, comm NUMBER)
AS
new_empno NUMBER;
BEGIN
SELECT empno_seq.NEXTVAL INTO new_empno FROM dual;
INSERT INTO emp VALUES (new_empno, ename, job,SYSDATE,
esal, comm);
DBMS_OUTPUT.PUT_LINE('employee inserted successfully');
END hire_fire_employee;
BEGIN
DELETE FROM emp WHERE empno = emp_id;
END emp_actions;
/
Step3:
SQL>select * from emp;
SQL>exec emp_actions.hire_fire_employee('vivek','IT',15789,0.3);
SQL>commit;
SQL>select * from emp;
SQL>exec emp_actions.hire_fire_employee(1);
SQL>select * from emp;
It is platform independents, so you do not need to deliver multiple versions of the same compilation
unit.
It permits dynamic binding loading, so users need not shut down and relink to add a new feature.
It permits dynamic binding, so external references are resolved at load time.
It offers strict dependency checking, so that invalidated program units are recompiled automatically
when they are invoked.
It supports normal importing and exporting, so the import/export utility can process wrapped files.
begin
dbms_output.put_line('hello dada');
end;
/
show errors
set serveroutput on
Step2:
1. 19. Create a package namedc get_schema_info. This package should have one
public procedure get_tb_count which will have 2 in parameters as follows.
1. schema_name in varchar2
2. sort_order in varchar2 default 'D'
(A for Asc D for desc)
This procedure disables calls to PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES, and purges
the buffer of any remaining information.
As with the ENABLE Procedure, you do not need to call this procedure if you are using the
SERVEROUTPUT option of SQL*Plus.
Syntax
DBMS_OUTPUT.DISABLE;
pragma restrict_references(disable,WNDS,RNDS);
This procedure enables calls to PUT, PUT_LINE, NEW_LINE, GET_LINE, and GET_LINES. Calls to these
procedures are ignored if the DBMS_OUTPUT package is not activated.
Syntax
It is not necessary to call this procedure when you use the SET SERVEROUTPUT option of SQL*Plus.
If there are multiple calls to ENABLE, then buffer_size is the last of the values specified. The
maximum size is 1,000,000, and the minimum is 2,000 when the user specifies buffer_size (NOT
NULL).
NULL is expected to be the usual choice. The default is 20,000 for backwards compatibility with
earlier database versions that did not support unlimited buffering.
Syntax:
DBMS_OUTPUT.GET_LINE (
line OUT VARCHAR2,
status OUT INTEGER);
Syntax
You can choose to retrieve from the buffer a single line or an array of lines. Call the GET_LINE
procedure to retrieve a single line of buffered information. To reduce the number of calls to the
server, call the GET_LINES procedure to retrieve an array of lines from the buffer.
You can choose to automatically display this information if you are using SQL*Plus by using the
special SET SERVEROUTPUT ON command.
After calling GET_LINE or GET_LINES, any lines not retrieved before the next call to PUT, PUT_LINE,
or NEW_LINE are discarded to avoid confusing them with the next message.
Syntax
DBMS_OUTPUT.PUT_LINE (
item IN VARCHAR2);
You can build a line of information piece by piece by making multiple calls to PUT, or place an entire
line of information into the buffer by calling PUT_LINE.
When you call PUT_LINE the item you specify is automatically followed by an end-of-line marker. If
you make calls to PUT to build a line, then you must add your own end-of-line marker by calling
NEW_LINE. GET_LINE and GET_LINES do not return lines that have not been terminated with a
newline character.
If your lines exceeds the line limit, you receive an error message.
Output that you create using PUT or PUT_LINE is buffered. The output cannot be retrieved until the
PL/SQL program unit from which it was buffered returns to its caller.
Example:
9.2 UTL_FILES
Procedures/Function Description
Opens a file for input or output with the default
FOPEN function
line size.
IS_OPEN function Determines if a file handle refers to an open file.
FCLOSE procedure Closes a file.
FCLOSE_ALL procedure Closes all open file handles.
GET_LINE procedure Reads a line of text from an open file.
Writes a line to a file. This does not append a line
PUT procedure
terminator
Writes one or more OS-specific line terminators
NEW_LINE procedure
to a file.
Writes a line to a file. This appends an OS-specific
PUT_LINE procedure line
terminator.
PUTF procedure A PUT procedure with formatting
FFLUSH procedure Physically writes all pending output to a file.
In addition to these package exceptions, procedures in UTL_FILE can also raise predefined PL/SQL
exceptions suchas NO_DATA_FOUND or VALUE_ERROR.
Syntax
UTL_FILE.FOPEN (
Location IN VARCHAR2,8
filename IN VARCHAR2,
open_mode IN VARCHAR2)
RETURN UTL_FILE.FILE_TYPE;
Parameters Description
Location Operating system-specific string that specifies
Note: If you open a file that does not exist using the 'a' value for open_mode, then the file is
created in write ('w') mode Returns.
FOPEN returns a file handle, whih must be passed to all subsequent procedures that operate on that
file. The specific contents of the file handle are private to the UTL_FILE package, and individual
components should not be referenced or changed by the UTL_FILE user.
Syntax:
UTL_FILE.IS_OPEN (
file IN FILE_TYPE)
RETURN BOOLEAN;
Syntax
UTL_FILE.FCLOSE (
file IN OUT FILE_TYPE);
UTL_FILE.FCLOSE_ALL;
Parameters Description
file Active file handle returned by an FOPEN call. The
file must be open for reading (mode 'r'),
otherwise an
INVALID_OPERATIONexception is raised.
Buffer Data buffer to receive the line read from the file.
Exceptions use:
INVALID_FILEHANDLE
INVALID_OPERATION
READ_ERROR
NO_DATA_FOUND
VALUE_ERROR
Parameters Description
File Active file handle returned by an FOPEN call.
Buffer Buffer that contains the text to be written to the
file.
You must have opened the file using mode 'w' or
mode 'a'; otherwise, anINVALID_OPERATION
Exceptions
INVALID_FILEHANDLE
INVALID_OPERATION
WRITE_ERROR
Syntax
UTL_FILE.PUT_LINE (
file IN FILE_TYPE,
buffer IN VARCHAR2);
Exceptions
INVALID_FILEHANDLE
INVALID_OPERATION
WRITE_ERROR
Syntax
UTL_FILE.FFLUSH ( file IN FILE_TYPE);
invalid_maxlinesize EXCEPTION;
Exceptions
INVALID_FILEHANDLE
INVALID_OPERATION
WRITE_ERROR
Syntax
UTL_FILE.FOPEN (
location IN VARCHAR2,
Parameter Description
Exceptions
It is utility for managing e-mail that includes such commonly used e-mail features as attachments,
CC, BCC and return receipt.
The UTL_MAIL Package is not installed by default because of the SMTP_OUT_SERVER configuration
requirement and the security exposure this involves, when installing UTL_MAIL you should take steps
to prevent the port defined by SMTP_OUT_SERVER being swamped by data transmission. To install
UTL_MAIL, login in as a DBA user in SQL*plus and execute the following scripts:-
@ORACLE_HOME/rdbms/admin/utlmail.sql
@ORACLE_HOME/rdbms/admin/prvtmail.plb
You should define the SMTP_OUT_SERVER parameter in the init.ora file database initialization file:-
SMTP_OUT_SERVER=mystmpserver.mydomain.com
The SMTP_OUT_SERVER parameter specifies the SMTP host and port to which UTL_MAIL delivers
outbound e-mail. Multiple servers can be specified, separated by the commas. If the first server in
the list is unavailable, then UTL_MAIL tries the second server, and so on. If SMTP_OUT_SERVER is not
defined, then this invokes a default setting derived from DB_DOMAIN ,which is a database
initialization parameter specifying for logical location of the database within the network structure
.For Example:-
db_domain=mydomain.com
BEGIN
UTL_MAIL.SEND (‘otn@oarcle.com’,’user@oracle.com’,
Message => ‘For latest downloads visit OTN’,
Subject => ‘OTN Newsletter’);
END;
The last example in the slide shows the simplest way to send a text message by using the
UTL_MAIL.SEND procedure with at least a subject and a message .The first two required parameter
are the following:
The recipients e-mail address (for example, user@oracle.com).The value can be a comma-separated
list of addresses.
The UTL_MAIL.SEND procedure provides several other parameters, such as cc, bcc and priority with
default values. if not specified. In the example, the message parameter specifies the text for the e-
mail,and the subject parameter contains the text for the subject line. To send an HTML message with
HTML tags, add the mime_type parameter (for example, mime_type=>’text/html’).
9.3.2 Example:
create or replace procedure sp27
--This Program shows
--How to send mails using UTL_MAIL package
as
ora_no number;
ora_msg varchar2(100);
begin
UTL_MAIL.SEND( sender => 'gaurav@server1.example.com',
recipients => 'gaurav@server1.example.com',
cc => 'mithilesh@server1.example.com',
bcc => 'krunal@server1.example.com',
subject => 'test mail', message => 'hi how r
u??');
OUTPUT
SQL> @sp27.sql
Procedure created.
No errors.
SQL> exec sp27
Message send successfully
PL/SQL procedure successfully completed.
The component that causes something to be executed at a specified time is called a Job. Use the
DBMS_SCHUDULER.CREATE_JOB procedure of the DBMS_SCHUDULER package to create a job,
which is in a disabled state by default. A jobs become active and scheduled when it is explicitly
enabled. To create a job, you:-
In simple turns, a job can be created specifying all the job details-the program to be executed (what)
and its schedule (when) - in the arguments of the CREATE JOB procedure. Alternatively, you can use
predefined program and schedule components. If you have a named program and schedule, then
these can be specified or combined with in-line arguments for maximum flexibility in the way a job is
created.
A simple logical check is performed on the schedule information (that is, checking the date
parameter when a job is created).The database checks whether the end date is after the start date .If
the start date refers to a time in the past, the start date is changed to the current date.
BEGIN
DBMS_SCHEDULER.CERATE_JOB (
Job_name => ’JOB_NAME’,
Job_type => ’PLSQL_BLOCK’,
Job_action => ’BEGIN….; END; ’,
tart_date =>SYSTIMESTAMP,
Repeat interval => ‘FREQUENCY=HOURLY; INTERVAL=1’,
Enabled => TRUE);
END;
/
You can create a job to run a PL/SQL block, stored procedure, or external program by using the
DBMS_SCHEDULER.CREATE_JOB procedure. The CREATE_JOB procedure can be used directly without
requiring you to create program or schedule components.
The example in the slide shows how you can specify all the job details in-line. The parameter of the
CREATE_JOB procedure define “what” is to be executed, the schedule, and other job attributes. The
following parameters define what is to be executed.
Note:-String expressions that are specified for repeat_interval are discussed later.
The example specifies that, the job should run every hour.
Run the job by calling the RUN_JOB procedure specifying the name of the job.The job is
immediately executed in your current session.
Stop the job by using the STOP_JOB procedure. If the job is running currently, it is stopped
immediately. The STOP_JOB procedure has two arguments:
- Job_name: -Is the name of the job to be stopped.
Force: -Attempts to gracefully terminate a job. If this fails and force is set to TRUE, then the job
slave is term If the DROP_JOB procedure is called and the job specified is currently running, then
the command fails unless the force option is set to TRUE. If the force option is set to TRUE, then
any instance of the job that is running is stopped and the job is dropped.
- inated.(Default value is FALSE).To use force, you must have the MANAGE_SCHUDULER system
privilege.
Drop the job with the DROP_JOB procedure. This procedure has two arguments:
- Job_name: -Is the name of the job to be dropped.
- Force: -Whether the job should be stopped and dropped if it is currently running. (Default
value is FALSE).
Example of DBMS_SCHEDULER
OUTPUT
15:04:48 SQL> truncate table test_sch;
Table truncated.
15:04:57 SQL> @sp28.sql
Procedure created.
No errors.
15:10:14 SQL> /
COUNT(*)
----------
300
15:10:27 SQL> /
COUNT(*)
----------
400
15:10:37 SQL> /
COUNT(*)
----------
500
15:10:46 SQL> /
COUNT(*)
----------
600
Focus Trainig Services, Pune Page 123
15:10:53 SQL> /
COUNT(*)
----------
600
The DBA_SCHEDULER_JOB_LOG view shows all completed job instances, both successful and failed.
To determine which instance a job is running on, use the following query:-
SELECT owner, job_name, running_instance, resource_consumer_group
FROM DBA_SCHEDULER_RUNNING_JOBS;
9.5.1 XMLTYPE
The easiest way to create an XML document, is using the constructor of XMLTYPE. This constructor
can have several datatypes as input, like a CLOB and VARCHAR2, but as we’re going to base our XML
on table data, we’re using a REF CURSOR.
You can create a ref cursor and pass on this ref cursor to the XMLTYPE constructor like this:
DECLARE
l_refcursor SYS_REFCURSOR;
l_xmltype XMLTYPE;
BEGIN
OPEN l_refcursor FOR SELECT department_id , department_name
FROM departments
WHERE department_id IN (10,20);
l_xmltype := XMLTYPE(l_refcursor);
dbms_output.put_line(l_xmltype.getClobVal);
END;
/
OUTPUT:
<?xml version="1.0"?>
<ROWSET>
<ROW>
<DEPARTMENT_ID>10</DEPARTMENT_ID>
<DEPARTMENT_NAME>Administration</DEPARTMENT_NAME>
</ROW>
<ROW>
<DEPARTMENT_ID>20</DEPARTMENT_ID>
9.5.2 DBMS_XMLGEN
The DBMS_XMLGEN built-in is similar to the XMLTYPE constructor, but accepts a query directly:
DECLARE
l_xmltype XMLTYPE;
BEGIN
l_xmltype := dbms_xmlgen.getxmltype('SELECT department_id ,
department_name
FROM departments
WHERE department_id IN (10,20)’);
OUTPUT:
<ROWSET>
<ROW>
<DEPARTMENT_ID>10</DEPARTMENT_ID>
<DEPARTMENT_NAME>Administration</DEPARTMENT_NAME>
</ROW>
<ROW>
<DEPARTMENT_ID>20</DEPARTMENT_ID>
<DEPARTMENT_NAME>Marketing</DEPARTMENT_NAME>
</ROW>
</ROWSET>
But it also provides procedures to change the ROWSET and ROW tags.
DECLARE
l_xmltype XMLTYPE;
l_ctx dbms_xmlgen.ctxhandle;
BEGIN
l_ctx := dbms_xmlgen.newcontext('SELECT department_id ,
department_name FROM departments WHERE department_id in (10,20)');
dbms_xmlgen.setrowsettag(l_ctx, 'Departments');
dbms_xmlgen.setrowtag(l_ctx, 'Dept');
l_xmltype := dbms_xmlgen.getXmlType(l_ctx) ;
dbms_xmlgen.closeContext(l_ctx);
dbms_output.put_line(l_xmltype.getClobVal);
End;
/
OUTPUT:
<Departments>
<Dept>
<DEPARTMENT_ID>10</DEPARTMENT_ID>
<DEPARTMENT_NAME>Administration</DEPARTMENT_NAME>
</Dept>
<Dept>
<DEPARTMENT_ID>20</DEPARTMENT_ID>
<DEPARTMENT_NAME>Marketing</DEPARTMENT_NAME>
</Dept>
</Departments>
With the XMLTYPE constructor and DBMS_XMLGEN package, you can create simple XML documents,
fast and easy. When you need to create more advanced XML documents or want to have more
control on how your XML document looks like, DBMS_XMLDOM can be used. The DBMS_XMLDOM
package is a bit more complicated as you’ll have to create the entire document by calling functions
and procedures of the package.
The following example creates an XML document with the department information retrieved from
the query. In short, this is how it works: create new elements and add them as a (child) node.
DECLARE
l_xmltype XMLTYPE;
l_domdoc dbms_xmldom.DOMDocument;
l_root_node dbms_xmldom.DOMNode;
l_department_element dbms_xmldom.DOMElement;
l_departments_node dbms_xmldom.DOMNode;
l_dept_element dbms_xmldom.DOMElement;
l_dept_node dbms_xmldom.DOMNode;
l_name_element dbms_xmldom.DOMElement;
l_name_node dbms_xmldom.DOMNode;
l_name_text dbms_xmldom.DOMText;
l_name_textnode dbms_xmldom.DOMNode;
l_location_element dbms_xmldom.DOMElement;
l_location_node dbms_xmldom.DOMNode;
l_location_text dbms_xmldom.DOMText;
l_location_textnode dbms_xmldom.DOMNode;
BEGIN
-- Create an empty XML document
l_domdoc := dbms_xmldom.newDomDocument;
-- Each Dept node will aslo get a Location node which contains
the location(city) as text
l_location_element := dbms_xmldom.createElement(l_domdoc,
'Location' );
l_location_node :=
dbms_xmldom.appendChild(l_dept_node,dbms_xmldom.makeNode(l_location_
element));
l_location_text := dbms_xmldom.createTextNode(l_domdoc,
r_dept.city );
l_location_textnode :=
dbms_xmldom.appendChild(l_location_node,dbms_xmldom.makeNode(l
_location_text));
END LOOP;
l_xmltype := dbms_xmldom.getXmlType(l_domdoc);
dbms_xmldom.freeDocument(l_domdoc);
dbms_output.put_line(l_xmltype.getClobVal);
END;
/
OUTPUT:
<Deptartments>
<Dept DeptID="10">
<Name>Administration</Name>
Focus Trainig Services, Pune Page 128
<Location>Seattle</Location>
</Dept>
<Dept DeptID="20">
<Name>Marketing</Name>
<Location>Toronto</Location>
</Dept>
</Deptartments>
Oracle never states in the documentation obfuscation is a secure solution, they say its obfuscation.
It would be interesting to see when Oracle will offer encryption tool for PL/SQL.
I suggest an account similar to the SYSTEM account. Remember that stored objects cannot be
created based on privileges from a role, so even the SYSTEM account must be given a direct grant on
the dba_tables view.
dbms_ddl.analyze schema: Oracle provides many ways to analyze SQL optimizer statistics,
and Oracle recommends using the dbms_stats package. It is not always a good idea to use
Oracle's dbms_utility.analyze_schema or the dbms_ddl.analyze_object packages to perform
this task.
It’s important for vendors who write applications using Oracle PL/SQL to protect their intellectual
property and encrypt their PL/SQL source code. Oracle has two method for encrypting PL/SQL, the
wrap.exe and the dbms_ddl.wrap utility in release 10.2 and onwards.
9.6.1 DBMS_DDL.WRAP
The dbms_ddl.wrap procedure accepts as input a parameter containing a PL/SQL create or replace
statement and dbms_ddl.wrap returns the obfuscated PL/SQL, which can be written to a file or
stored in a table.. The outstanding example of using the dynamic PL/SQL encryption function:
OUTPUT:
a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
6f
aa
mV4eMSJ8EqqgErJT91l6UZ0pdDUwgyr6LZ5GfHSmUPiJfkEObQpeDb6D7glajI+ONulx
dqC1
0HvOPP4eJpQs5zxsKXpj6XL1
fvieXyWCr3BTzXTqcGYhfXrtqDVPztR/o+9UZ8l5OijDSsRW
ZPv6rISzFyqeEsCBweFUFyxd
In addition to the wrap functions, the dbms_ddl package also contains three overloaded procedures
called create_wrapped. These procedure have the same parameter lists as the three wrap function
overloads, and are used to wrap and compile the specified source. The following example shows
how the dbms_sql.varchar2a version is used:
Step1:
Step2:
SELECT text
FROM user_source
WHERE name = 'GET_DATE_STRING'
AND type = 'FUNCTION';
TEXT
--------------------------------------------------------------------
----
FUNCTION get_date_string wrapped
a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
6f aa
mV4eMSJ8EqqgErJT91l6UZ0pdDUwgyr6LZ5GfHSmUPiJfkEObQpeDb6D7glajI+ONulx
dqC1
0HvOPP4eJpQs5zxsKXpj6XL1fvieXyWCr3BTzXTqcGYhfXrtqDVPztR/o+9UZ8l5OijD
SsRW
ZPv6rISzFyqeEsCBweFUFyxd
A trigger:
• Is a PL/SQL block or a PL/SQL procedure associated with a table, view, schema, or the database
• Executes implicitly whenever a particular event takes place
Database triggers execute implicitly when a data event such as DML on a table (an INSERT, UPDATE,
or DELETE triggering statement), an INSTEAD OF trigger on a view, or data definition language (DDL)
statements such as CREATE and ALTER are issued, no matter which user is connected or which
application is used. Database triggers also execute implicitly when some user actions or database
system actions occur, for example, when a user logs on, or the DBA shut downs the database.
Note: Database triggers can be defined on tables and on views. If a DML operation is issued on a
view, the INSTEAD OF trigger defines what actions take place. If these actions include DML operations
on tables, then any triggers on the base tables are fired.Database triggers can be system triggers on a
Focus Trainig Services, Pune Page 133
database or a schema. With a database, triggers fire for each event for all users; with a schema,
triggers fire for each event for that specific user.
• Create stored procedures and invoke them in a trigger, if the PL/SQL code is very
lengthy.
• The excessive use of triggers can result in complex interdependencies, which may be difficult to
maintain in large applications.
Example:
OUTPUT:
SQL> @14_1.sql
Trigger created.
No errors.
• Trigger timing
Before coding the trigger body, decide on the values of the components of the trigger: the trigger
timing, the triggering event, and the trigger type.
If multiple triggers are defined for a table, be aware that the order in which multiple triggers of the
same type fire is arbitrary. To ensure that triggers of the same type are fired in a particular order,
consolidate the triggers into one trigger that calls separate procedures in the desired order.
The triggering event or statement can be an INSERT, UPDATE, or DELETE statement on a table.
. . UPDATE OF salary . . .
• The triggering event can contain one, two, or all three of these DML operations.
. . . INSERT or UPDATE or DELETE
. . . INSERT or UPDATE OF job_id . . .
Example:
OUTPUT:
SQL> @sp14_2.sql
Trigger created.
No errors.
Should the trigger body execute for each row the statement affects or only once?
Statement: The trigger body executes once for the triggering event. This is the default. A
statement trigger fires once, even if no rows are affected at all.
Row: The trigger body executes once for each row affected by the triggering event. A row trigger
is not executed if the triggering event affects no rows. Statement Triggers and Row Triggers
You can specify that the trigger will be executed once for every row affected by the triggering
statement (such as a multiple row UPDATE) or once for the triggering statement, no matter how
many rows it affects.
Example:
Step1:
SQL> create table deptcopy as select * from departments;
Step2:
Step3:
OUTPUT:
Trigger created.
END;
/
Within a ROW trigger, reference the value of a column before and after the data change by prefixing
it with the OLD and NEW qualifier
OUTPUT:
Update Employees
*
ERROR at line 1:
ORA-20202: Employee can not this amount
ORA-06512: at “PL/SQL.RESTRICT_SALARY”, line 5
ORA-04088: error during execution of trigger
‘PLSQL.RESTRICTp_SALARY’
The OLD and NEW qualifiers are available only in ROW triggers.
• Prefix these qualifiers with a colon (:) in every SQL and PL/SQL statement.
• There is no colon (:) prefix if the qualifiers are referenced in the WHEN restricting condition.
Note: Row triggers can decrease the performance if you do a lot of updates on larger tables. To
restrict the trigger action to those rows that satisfy a certain condition, provide a WHEN clause.
Create a trigger on the EMPLOYEES table to calculate an employee’s commission when a row is
added to the EMPLOYEES table, or when an employee’s salary is modified. The NEW qualifier cannot
be prefixed with a colon in the WHEN clause because the WHEN clause is outside the PL/SQL blocks.
Use INSTEAD OF triggers to modify data in which the DML statement has been issued against an
inherently non-updatable view. These triggers are called INSTEAD OF triggers because, unlike other
triggers, the Oracle server fires the trigger instead of executing the triggering statement. This trigger
is used to perform an INSERT, UPDATE, or DELETE operation directly on the underlying tables.
You can write INSERT, UPDATE, or DELETE statements against a view, and the INSTEAD OF trigger
works invisibly in the background to make the right actions take place.
Parameters of Triggers:
INSERT
DELETE,
row trigger.
a call to a procedur
Note: INSTEAD OF triggers can be written only for views. BEFORE and AFTER options are not valid.
You can create an INSTEAD OF trigger in order to maintain the base tables on which a view is based.
Assume that an employee name will be inserted using the view EMP_DETAILS that is created based
on the EMPLOYEES and DEPARTMENTS tables. Create a trigger that results in the appropriate INSERT
and UPDATE to the base tables. Because of the INSTEAD OF TRIGGER on the view EMP_DETAILS,
instead of inserting the new employee record into the EMPLOYEES table:
• A row is inserted into the NEW_EMPS table.
• TheTOTAL_DEPT_SAL column of the NEW_DEPTS table is updated. The salary value
supplied for the new employee is added to the existing total salary of the department to
which the new employee has been assigned.
1. We can execute a stored procedure whenever we want with the help of the exec command,
but a trigger can only be executed whenever an event (insert, delete, and update) is fired on
the table on which the trigger is defined.
2. We can call a stored procedure from inside another stored procedure but we can't directly
call another trigger within a trigger. We can only achieve nesting of triggers in which the
action (insert, delete, and update) defined within a trigger can initiate execution of another
trigger defined on the same table or a different table.
3. Stored procedures can be scheduled through a job to execute on a predefined time, but we
can't schedule a trigger.
4. Stored procedure can take input parameters, but we can't pass parameters as input to a
trigger.
5. Stored procedures can return values but a trigger cannot return a value.
Triggers are fully compiled when the CREATE TRIGGER command is issued and the P code is
stored in the data dictionary. If errors occur during the compilation of a trigger, the trigger is still
created.
Example:
DROP TRIGGER secure_emp;
Step2:
UPDATE employees SET department_id = 999
WHERE employee_id = 170;
-- Successful after trigger is fired
The example in the slide explains a situation in which the integrity constraint can be taken care of by
using a trigger. Table EMPLOYEES has a foreign key constraint on the DEPARTMENT_ID column of the
DEPARTMENTS table.
In the first SQL statement, the DEPARTMENT_ID of the employee with EMPLOYEE_ID 170 is modified
to 999. Because such a department does not exist in the DEPARTMENTS table, the statement raises
the exception -2292 for the integrity constraint violation.
A trigger CONSTR_EMP_TRIG is created that inserts a new department 999 into the DEPARTMENTS
table.
When the UPDATE statement that modifies the department of employee 170 to 999 is issued, the
trigger fires. Then, the foreign key constraint is checked. Because the trigger inserted the department
999 into the DEPARTMENTS table, the foreign key constraint check is successful and there is no
exception.
Practice Example:
1)Create a trigger to allow only certain employees to be able to earn a salary of more than 15,000.
Declare variables to store the name, job, and salary of a new employee.
Example:
...
TYPE emp_record_type IS RECORD
(last_name VARCHAR2(25),
job_id VARCHAR2(10),
Field declarations are like variable declarations. Each field has a unique name and a specific data
type. There are no predefined data types for PL/SQL records, as there are for scalar variables.
Therefore, you must create the record type first and then declare an identifier using that type. In the
example on the slide, a EMP_RECORD_TYPE record type is defined to hold the values for the
last_name, job_id, and salary. In the next step, a record EMP_RECORD, of the type
EMP_RECORD_TYPE is declared.
Note: You can add the NOT NULL constraint to any field declaration to prevent assigning nulls to that
field. Remember, fields declared as NOT NULL must be initialized.
record_name.field_name
DECLARE
emp_record employees%ROWTYPE;
Syntax:
DECLARE
identifier reference%ROWTYPE;
where: identifier is the name chosen for the record as a whole. reference is the name of the table,
view, cursor, or cursor variable on which the record is to be based. The table or view must exist for
this reference to be valid. To reference an individual field, you use dot notation and the following
syntax:
record_name.field_name
The number and data types of the underlying database column may change at run
time.
The attribute is useful when retrieving a row with the SELECT * statement.
11.6 VARRAY
They are densely populated arrays (no gaps in the index sequence) and behave like traditional
programming arrays. They can be accessed by either SQL or PL/SQL, at creation they have a fixed size
which cannot be changed. Varrays use sequential integers for there subscripts (index), however the
subscript starts from 1 not 0.
Varrays are single dimensional structures which can be used in table, record and object definitions,
they can be accessed via both SQL and PL/SQL. Varrays have to be defined, declared and initialized
also remember that the subscript starts at 1 not 0
Example:
declare
type int_array is varray(5) of number;
Output:
SQL> @ap1.sql
The sorted array is:=
7
6
4
3
1
Example 2:
declare
Output:
SQL> @ap2.sql
Array Elements are:
ABC
XYZ
Step1:
Step2:
declare
c1 card1:=card1(null,null,null);
begin
c1(1):='Ace';
c1(2):='Two';
c1(3):='Three';
dbms_output.put_line('Array Elements:');
for i in 1..3
loop
dbms_output.put_line(c1(i));
end loop;
end;
/
Step3:
Output:
SQL> @ap3.sql
Type created.
Array Elements:
Ace
Two
Three
Note: extend is a method that adds a new empty element to a nested table, this must be called
first.
You cannot store an associative array directly in the database, so you need logic to store and retrieve
the values in this type of collection with the database, it also cannot be use in SQL.Varrays and
Nested tables
Example:
create or replace procedure asso1
is
asso1(arr1(1)):='Ant';
asso1(arr1(2)):='Bat';
asso1(arr1(3)):='Cat';
asso1(arr1(4)):='Deer';
asso1(arr1(5)):='Egg';
Output:
SQL> @ap4.sql
ddl event occure
Procedure created.
At a given point of time, a Associative Array can store only the details of any one of the columns of a
database table. There is always a necessity to store all the columns retrieved by a query. The
Associative Array of records offers a solution to this. Because only one table definition is needed to
hold information about all of the fields of a database table, the table of records greatly increases the
functionality of Associative Arrays.
11.9 Summary
In this chapter, you should have learned to:
• Define and reference PL/SQL variables of composite data types:
– PL/SQL records
– Associative Arrays
– Associative Array of records
–
• Define a PL/SQL record by using the %ROWTYPE attribute
A PL/SQL record is a collection of individual fields that represent a row in a table. By using records
you can group the data into one structure and then manipulate this structure as one entity or logical
unit. This helps reduce coding, and keeps the code easier to maintain and understand.
Like PL/SQL records, the table is another composite data type. Associative Arrays are objects of a
TABLE type and look similar to database tables but with a slight difference. Associative Arrays use a
primary key to give you array-like accessto rows. The size of a Associative Array is unconstrained.
Associative Arrays can have one column and a primary key, neither of which can be named. The
column can have any data type, but the primary key must be of the BINARY_INTEGER type.
Output:
SQL> @ap8.sql
Procedure created.
Too many context switches between the PL/SQL and SQL engines can harm performance. That can
happen when a loop executes a separate SQL statement for each element of a collection, specifying
in-bind When a PL/SQL variable or host variable is stored in the database by an INSERT or
UPDATE statement.
out-bind When a database value is assigned to a PL/SQL variable or a host variable by the
RETURNING clause of an INSERT, UPDATE, or DELETE statement.
Step2:
DECLARE
TYPE NumTab IS TABLE OF NUMBER(4) INDEX BY BINARY_INTEGER;
TYPE NameTab IS TABLE OF CHAR(15) INDEX BY BINARY_INTEGER;
pnums NumTab;
pnames NameTab;
BEGIN
FOR j IN 1..5000 LOOP -- load index-by tables
pnums(j) := j;
pnames(j) := ’Part No. ’ || TO_CHAR(j);
END LOOP;
t1 := dbms_utility.get_time;
FOR i IN 1..5000 LOOP -- use FOR loop
INSERT INTO parts VALUES (pnums(i), pnames(i));
END LOOP;
t2 := dbms_utility.get_time;
FORALL i IN 1..5000 -- use FORALL statement
INSERT INTO parts VALUES (pnums(i), pnames(i));
get_time(t3);
dbms_output.put_line(’Execution Time (secs)’);
dbms_output.put_line(’---------------------’);
dbms_output.put_line(’FOR loop: ’ || TO_CHAR(t2 - t1));
dbms_output.put_line(’FORALL: ’ || TO_CHAR(t3 - t2));
END;
Step3:
SQL> /
Execution Time (secs)
---------------------
FOR loop: 32
FORALL: 3
PL/SQL procedure successfully completed.
The index can be referenced only within the FORALL statement and only as a collection subscript. The
SQL statement must be an INSERT, UPDATE, or DELETE statement that references collection
elements. And, the bounds must specify a valid range of consecutive index numbers. The SQL engine
executes the SQL statement once for each index number in the range.
To process SQL data manipulation statements, the SQL engine opens an implicitcursor named SQL.
This cursor’s scalar attributes, %FOUND, %ISOPEN,
%NOTFOUND, and %ROWCOUNT, return useful information about the most recently executed SQL
data manipulation statement.
The SQL cursor has one composite attribute, %BULK_ROWCOUNT, designed for use with the FORALL
statement. This attribute has the semantics of an index-by table. Its ith element stores the number of
rows processed by the ith execution of an INSERT, UPDATE or DELETE statement. If the ith execution
affects no rows, %BULK_ROWCOUNT(i) returns zero. An example follows:
DECLARE
TYPE NumList IS TABLE OF NUMBER;
depts NumList := NumList(10, 20, 50);
BEGIN
FORALL j IN depts.FIRST..depts.LAST
UPDATE emp SET sal = sal * 1.10 WHERE deptno = depts(j);
-- Did the 3rd UPDATE statement affect any rows?
IF SQL%BULK_ROWCOUNT(3) = 0 THEN ...
END;
/
PL/SQL provides a mechanism to handle exceptions raised during the execution of a FORALL
statement. This mechanism enables a bulk-bind operation to save information about exceptions and
continue processing.
To have a bulk bind complete despite errors, add the keywords SAVE EXCEPTIONS to your FORALL
statement. The syntax follows:
FORALL index IN lower_bound..upper_bound SAVE EXCEPTIONS {insert_stmt | update_stmt |
delete_stmt}
All exceptions raised during the execution are saved in the new cursor attribute %BULK_EXCEPTIONS,
which stores a collection of records. Each record has two fields. The first field,
%BULK_EXCEPTIONS(i).ERROR_INDEX, holds the "iteration" of the FORALL statement during which
the exception was raised. The second field, %BULK_EXCEPTIONS(i).ERROR_CODE, holds the
corresponding Oracle error code.
The values stored by %BULK_EXCEPTIONS always refer to the most recently executed FORALL
statement. The number of exceptions is saved in the count attribute of %BULK_EXCEPTIONS, that is,
%BULK_EXCEPTIONS.COUNT. Its subscripts range from 1 to COUNT.
If you omit the keywords SAVE EXCEPTIONS, execution of the FORALL statement stops when an
exception is raised. In that case, SQL%BULK_EXCEPTIONS.COUNT returns 1, and
In this example, PL/SQL raised the predefined exception ZERO_DIVIDE when I equalled 2, 6, 10. After
the bulk-bind completed, SQL%BULK_EXCEPTIONS.COUNT returned 3, and the contents of
SQL%BULK_EXCEPTIONS were (2,1476), (6,1476), and (10,1476). To get the Oracle error message
(which includes the code), we negated the value of SQL%BULK_EXCEPTIONS(i).ERROR_CODE and
passed the result to the error-reporting function SQLERRM, which expects a negative number.Here is
the
OUTPUT:
Number of errors is 3
Error 1 occurred during iteration 2
12.6 Retrieving Query Results into Collections with the BULK COLLE Clause
The keywords BULK COLLECT tell the SQL engine to bulk-bind output collections before returning
them to the PL/SQL engine. You can use these keywords in the SELECT INTO, FETCH INTO, and
RETURNING INTO clauses.
Here is the syntax:
... BULK COLLECT INTO collection_name[, collection_name] ...
The SQL engine bulk-binds all collections referenced in the INTO list. The corresponding columns can
store scalar or composite values including objects. In the following example, the SQL engine loads the
entire empno and ename database columns into nested tables before returning the tables to the
PL/SQL engine:
DECLARE
TYPE NumTab IS TABLE OF emp.empno%TYPE;
TYPE NameTab IS TABLE OF emp.ename%TYPE;
enums NumTab; -- no need to initialize
names NameTab;
BEGIN
SELECT empno, ename BULK COLLECT INTO enums, names FROM emp;
...
END;
/
The SQL engine initializes and extends collections for you. (However, it cannot extend varrays beyond
their maximum size.) Then, starting at index 1, it inserts elements consecutively and overwrites any
pre-existent elements. The SQL engine bulk-binds entire database columns. So, if a table has 50,000
rows, the engine loads 50,000 column values into the target collection. However, you can use the
pseudocolumn ROWNUM to limit the number of rows processed.
Limiting the Rows for a Bulk FETCH Operation with the LIMIT Clause
The optional LIMIT clause, allowed only in bulk (not scalar) FETCH statements, lets you limit the
number of rows fetched from the database. The syntax is
where rows can be a literal, variable, or expression but must evaluate to a number. Otherwise,
PL/SQL raises the predefined exception VALUE_ERROR. If the number is not positive, PL/SQL raises
INVALID_NUMBER. If necessary, PL/SQL rounds the number to the nearest integer.
Focus Trainig Services, Pune Page 170
Retrieving DML Results into a Collection with the RETURNING INTO Clause
You can use the BULK COLLECT clause in the RETURNING INTO clause of an INSERT, UPDATE, or
DELETE statement, as the following example shows:
DECLARE
TYPE NumList IS TABLE OF emp.empno%TYPE;
enums NumList;
BEGIN
DELETE FROM emp WHERE deptno = 20
RETURNING empno BULK COLLECT INTO enums;
-- if there were five employees in department 20,
-- then enums contains five employee numbers
END;
/
The column values returned by each execution are added to the values returned previously. (With a
FOR loop, the previous values are overwritten.)
You cannot use the SELECT ... BULK COLLECT statement in a FORALL statement. Otherwise, you get
the error implementation restriction: cannot use FORALL and BULK COLLECT INTO together in
SELECT statements.
12.9 Summary
In this chapter, we learned that Binding an entire collection at once is called bulk binding. Bulk binds
improve performance by minimizing the number of context switches between the PL/SQL and SQL
engines. With bulk binds, entire collections, not just individual elements, are passed back and forth.
The keyword FORALL instructs the PL/SQL engine to bulk bind input collections before sending them
to the SQL engine. Although the FORALL statement contains an iteration scheme, it is not a FOR loop.
Tuning performance with bulk binds and reduce loop overhead for collections. Bulk collect and
restrictions in using bulk collect.
REF type
The keyword REF implies that the new type so defined is a pointer to the defined type. PL/SQL offers two
types of REF types: CURSOR and an object type. So, the definition of a cursor variable involves the
definition of a REF CURSOR first, as shown here:
TYPE rc IS REF CURSOR;
This code suggests that rc is a pointer of type CURSOR and v_rc (in fact, any variable) defined of type
rc points to a SQL cursor.
Here, ref_type_name is the name of the new pointer name and return_type is a record type of either
%ROWTYPE or a user-defined record type. For example, you can declare strong REF CURSORS as
follows:
The following sections provide more detail about each step in the process.
You open a cursor variable using the OPEN-FOR statement. Here’s the syntax:
v_rc:
DECLARE
TYPE rc is REF CURSOR;
v_rc rc;
BEGIN
OPEN v_rc FOR SELECT * from hrc_tab;
/* . . . FETCH the results and process the resultset */
END;
13.4.3 Fetching the Results into a PL/SQL Record or Individual PL/SQL Variables
The next step is to fetch the cursor variable into a PL/SQL record or individual variables. This retrieves
individual rows of data into the PL/SQL variables for processing. You fetch a cursor variable using the
FETCH statement, which has three forms. Here’s the
syntax:
Here, var1, var2, and varN represent PL/SQL variables having data types identical to the cursor
variable query. table_name%ROWTYPE represents a PL/SQL record type with attributes implicitly
defined as the column names of the table identified by table_name, which are identical to the cursor
variable SELECT. In this case, you need to explicitly define the record type. Lastly, record_name is a
variable of a PL/SQL record type that’s explicitly defined. In this case also, the number and data types
of the individual attributes of the record should exactly match the columns in the cursor variable
SELECT. Here’s an example that extends the previous example of v_rc to fetching rows:
DECLARE
TYPE rc is REF CURSOR;
The number and data types of the individual variables should exactly match the columns list in the
cursor variable’s associated SELECT statement. If the cursor is fetched into a record type (either
table_name%ROWTYPE or record_name), the number and data type of each attribute in the record
should exactly match the columns list of the cursor variable associated SELECT statement. If this isn’t
the case, then PL/SQL raises an error at compile time if the cursor variable is strongly typed, and a
predefined exception called ROWTYPE_MISMATCH at runtime if the cursor variable is weakly typed.
OUTPUT:
This code is similar to the code used for static cursors, except that it uses cursor variables instead of
cursors.
DECLARE
TYPE rc is REF CURSOR;
v_rc1 rc;
v_rc2 rc;
hrc_rec hrc_tab%ROWTYPE;
BEGIN
OPEN v_rc1 FOR SELECT * from hrc_tab;
dbms_output.put_line(‘Hierarchy Details’);
dbms_output.put_line(‘------------------------’);
dbms_output.put_line(‘Code’||’ ‘||rpad(‘Description’,20,’ ‘));
dbms_output.put_line(rpad(‘-’,4,’-’)||’ ‘||rpad(‘-’,20,’- ’));
/* Assign v_rc1 to v_rc2 */
v_rc2 := v_rc1;
LOOP
/* Fetch from the second cursor variable, i.e., v_rc2
*/
FETCH v_rc2 INTO hrc_rec;
EXIT WHEN v_rc2%NOTFOUND;
dbms_output.put_line(to_char(hrc_rec.hrc_code)||’ ‘||
rpad(hrc_rec.hrc_descr,20,’ ‘));
END LOOP;
CLOSE v_rc2;
END;
/
The output of this program is the same as the output of the earlier example without the assignment.
Note that closing v_rc2 also closes v_rc1 and vice versa. However, if the source cursor variable is
strongly typed, the target cursor variable must be of the same type as the source cursor variable. This
restriction doesn’t apply if the source cursor variable is weakly typed. Here’s an example that
illustrates this concept
DECLARE
TYPE rc1 is REF CURSOR RETURN hrc_tab%ROWTYPE;
TYPE rc2 is REF CURSOR RETURN hrc_tab%ROWTYPE;
Hierarchy Details
-------------------------
Code Description
------ --------------
1 CEO/COO
2 VP
3 Director
Autonomous Transactions
Objectives
A transaction as a serious of statements that does a logical of work that completes or fails as an
integrated unit. Often , One transaction start another that many need to operate outside the scope
of the transaction that started it. That is , in an existing transaction, a required independent
transaction may need to commit or rollback changes without affecting the outcome of the starting
transaction. For example, in a stock purchase transaction , the customer’s information must be
committed regardless of whether the overall stock purchase completes. Or, while running that same
transaction, you want to log massages to a table even if the overall transaction rollback .
Since Oracle 8i, the autonomous transaction were added to make it possible to care an independent
transaction, An autonomous transaction (AT) is an independent transaction started by another main
transaction (MT), The slide depicts the behavior of an AT:
Changes made by an autonomous transaction become visible to other transactions when their
stack-like functionality, only the “top” transaction is accessible at any givine time. After
completion, the autonomous transactioni is popped, and the calling transaction is resumed
There are no limits other than resource limits on how may autonomous transactions can be
recursively called.
You cannot use PRAGMA to marked all subprograms in a packages as autonomous. Only
individual routines can be marked autonomous.
Step3:
OUTPUT :
SQL> @ap17.sql
Procedure created.
Procedure created.
Step4:
ID NAME
---------- ------------------------------
2 pqr
In the example in the slide, you track where the bankcard is used, regardless of whether the
transaction is successful. The following are benefits of autonomous transactions:
More important, sutonomous transactions help you build modular , reusable software
components. nFor example, stored procedure can start and finish autonomous transactions on
thir own. A calling application need not know about a procedure’s autonomous operations, and
the procedure need not know about the application’s transaction context. That makes
autonomous transactions less error-prone then regular transaction and easier to use
1) You want to execute a SQL data definition statement (such as CREATE), a data control
2) You want more flexibility. For example, you might want to defer your choice of schema
objects until run time. Or, you might want your program to build different search conditions for the
WHERE clause of a SELECT statement. A more complex program might choose from various
3) You use package DBMS_SQL to execute SQL statements dynamically, but you want
better performance, something easier to use, or functionality that DBMS_SQL lacks such as
where dynamic_string is a string expression that represents a SQL statement or PL/SQL block,
define_variable is a variable that stores a selected column value, and record is a user-defined or
%ROWTYPE record that stores a selected row.
begin
open c2;
loop
dbms_output.put_line(rpad('TABLE NAME',20)||'COUNT');
dbms_output.put_line('-----------------------------------------
--');
fetch c2 into r1;
exit when c2%notfound;
dbms_output.put_line(rpad(r1.tname,20)||r1.cnt1);
end loop;
close c2;
end;
/
show error
set serveroutput on
Example2:
create or replace procedure dyn2
is
cursor c1 is select table_name from user_tables;
r1 c1%rowtype;
cnt number;
sql1 varchar2(200);
sql2 varchar2(200);
OUTPUT:
Output:
SQL*Loader Basics
SQL*Loader loads data from external files into tables of an Oracle database.
SQL*Loader:
Has a powerful data parsing engine which puts little limitation on the format of the
data in the datafile.
Can load data from multiple datafiles during the same load session.
Can load data into multiple tables during the same load session.
Is character set aware (you can specify the character set of the data).
Can selectively load data (you can load records based on the records' values).
Can manipulate the data before loading it, using SQL functions.
Can generate unique sequential key values in specified columns.
Can use the operating system's file system to access the datafile(s).
Can load data from disk, tape, or named pipe.
Does sophisticated error reporting which greatly aids troubleshooting.
Supports two loading "paths" -- Conventional and Direct. While conventional path loading is very
flexibility,direct path loading provides superior loading performance.
Can load arbitrarily complex object-relational data.
E. SQL*Loader Rejects
Records are rejected by SQL*Loader when the input format is invalid. For example, if the second
enclosure delimiter is missing, or if a delimited field exceeds its maximum length, SQL*Loader rejects
the record. Rejected records are placed in the bad file.
Oracle Rejects
After a record is accepted for processing by SQL*Loader, a row is sent to Oracle for insertion. If
Oracle determines that the row is valid, then the row is inserted into the database. If not, the record
is rejected, and SQL*Loader puts it in the bad file. The row may be rejected, for example, because a
key is not unique, because a required field is null, or because the field contains invalid data for the
Oracle datatype.
The bad file is written in the same format as the datafile. So rejected data can be loaded with the
existing control file after necessary corrections are made.
never creates tables, it loads existing tables. Tables may already contain data, or they may be empty.
The following privileges are required for a load: You must have INSERT privileges on the table to be
loaded. You must have DELETE privilege on the table to be loaded, when using the REPLACE or
TRUNCATE option to empty out the table's old data before loading the new data in its place.
Conventional Path
During conventional path loads, the input records are parsed according to the field specifications,
and each data field is copied to its corresponding bind array. When the bind array is full (or there
is no more data left to read), an array insert is executed. Note that SQL*Loader stores LOB fields
after a bind array insert is done. Thus, if there are any errors in processing the LOB field (for
example, the LOBFILE could not be found), the LOB field is left empty.
There are no special requirements for tables being loaded via the conventional path.
Delimited File
load data
load data
replace -- you can use truncate to improve performance
into table departments
( dept position (02:05) char(4),
deptname position (08:27) char(20)
)
How to load
sqlldr userid=shekhar/shekhar control=emp.ctl
data=emp.dat log=emp.log bad=emp.bad reject=emp.reject
direct=true errors=1000 skip=1
The Oracle Relational Database Management System, or RDBMS, is designed to allow simultaneous
access to large amounts of stored information. The RDBMS consists of the database (the information)
and the instance (the embodiment of the system). The database contains the physical files that
reside on the system and the logical pieces such as the database schema. These database files take
various forms, as described in the following section. The instance is the method used to access the
data and consists of processes and system memory.
A. The Database
The Oracle database has a logical layer and a physical layer. The physical layer consists of the files
that reside on the disk; the components of the logical layer map the data to these physical
components.
The database is divided into one or more logical pieces known as tablespaces. A tablespace is used to
logically group data together. For example, you can create one tablespace for accounting and a
separate tablespace for purchasing. Segmenting groups into different tablespaces simplifies the
administration of these groups. Tablespaces consist of one or more datafiles. By using more than one
datafile per tablespace, you can spread data over many different disks to distribute the I/O load and
improve performance.
Extents
Extents are the building blocks of segments; in turn, they consist of data blocks. An extent is used to
minimize the amount of wasted (empty) storage. As more and more data is entered into tablespaces
in your database, the extents used to store that data can grow or shrink as necessary. In this manner,
many tablespaces can share the same storage space without preallocating the divisions between
those tablespaces. At tablespace-creation time, you can specify the minimum number of extents to
allocate as well as the number of extents to add at a time when that allocation has been used. This
arrangement gives you efficient control over the space used in your database.
Data Blocks
Data blocks are the smallest pieces of an Oracle database; they are physically stored on disk.
Although the data block in most systems is 2KB (2,048 bytes), you can change this size for efficiency
depending on your application or operating system.
Processes
In many operating systems, traditional processes have been replaced by threads or lightweight
processes. The term process is used in this book to describe a thread of execution, or a mechanism
that can execute a set of code; process refers to the mechanism of execution and can refer to a
traditional process or a thread.
The Oracle RDBMS uses two types of processes: user processes and Oracle processes (also known as
background processes). In some operating systems (such as Windows NT), these processes are
actually threads; for the sake of consistency, I will refer to them as processes.
User Processes
User, or client, processes are the user's connections to the RDBMS system. The user process
manipulates the user's input and communicates with the Oracle server process through the Oracle
program interface. The user process is also used to display the information requested by the user
and, if necessary, can process this information into a more useful form.
Oracle Processes
Oracle processes perform functions for users. Oracle processes can be split into two groups: server
processes (which perform functions for the invoking process) and background processes (which
perform functions on behalf of the entire RDBMS).
Oracle Database 12c offers a variety of enhancements to the way you can define and execute PL/SQL
program units. This article covers several new Oracle Database 12c features that enable you to do
the following:
Oracle Database 11g introduced the PL/SQL function result cache, which offers a very powerful,
efficient, and easy-to-use caching mechanism. The main objective of this cache is to ensure that if a
row of data hasn’t changed since it was last fetched from the database, no SQL statement needs to
execute for it to be retrieved again.
This holds true across the entire database instance. In other words, suppose a user connected to
schema USER_ONE executes a result-cached function to retrieve the row from the employees table
for employee ID = 100. When a user connected to schema USER_TWO executes the same function
call for the same employee ID, that row of information is retrieved directly from the cache and not by
execution of a SELECT statement.
If you are not already using this feature (and you are using Oracle Database 11g), I strongly
encourage you to investigate it and start applying it—in close collaboration with your DBA so that the
result cache pool is sized properly.
Even in Oracle Database 11g Release 2, however, you could not combine invoker rights (AUTHID
CURRENT_USER clause) with the function result cache (RESULT_CACHE keyword). An attempt to
compile the following function:
RETURN l_return;
END;
/
The reason for this restriction is the whole point of invoker rights. At runtime the PL/SQL engine uses
the privileges of the current user to resolve references to database objects such as tables and views.
But if such a function was compiled with RESULT_CACHE, then (using the example above) after
USER_ONE executed the function, passing in 100, when USER_TWO makes the same function call,
the body of the function would not be executed and the reference to the EMPLOYEES table would
not be resolved according to USER_TWO’s privilege. This could have caused serious security issues.
Well, the good news is that this restriction was temporary. In Oracle Database 12c, you can now
compile functions such as last_name (above) without error—and Oracle Database 12c does the right
thing, of course.
Behind the scenes, Oracle Database 12c passes the name of the current user as a hidden parameter;
this value is cached along with the values of all the arguments passed to the function. So each time
the last_name function is called, Oracle Database 12c checks to see if that function has been
previously called with both the same employee ID and the same current user.
This means that the result cache for an invoker rights function is (logically) partitioned by the name
of the current user. Consequently, the result cache for an invoker rights function will improve
performance only in situations in which the same user calls the function with the same argument
values repeatedly. Another way of explaining this is to point out that in Oracle Database 11g Release
2, I could have achieved the same effect, but only if I had changed the implementation of the
last_name function, as shown in Listing 1.
RETURN l_return;
END;
FUNCTION last_name (
employee_id_in IN employees.employee_id%TYPE)
RETURN employees.last_name%TYPE
IS
l_return employees.last_name%TYPE;
BEGIN
RETURN i_last_name (employee_id_in,
USER);
END;
END;
/
Note that the last_name function is defined in the package specification and is not result-cached.
Instead, that public function (declared in the package specification) merely calls the private/internal
“version” of the function, which has a second parameter: the user.
So each time you call employee_api.last_name, Oracle Database 11g Release 2 adds the name of the
user to the set of values used by the database to determine whether there is a match in the result
cache.
This is no longer necessary; in Oracle Database 12c, you simply need to decide if you think it is worth
adding RESULT_CACHE to invoker rights programs.
Developers have long been able to call their own PL/SQL functions from within a SQL statement.
Suppose, for example, I have created a function named BETWNSTR that returns the substring
between the specified start and end locations:
FUNCTION betwnstr (
string_in IN VARCHAR2
, start_in IN PLS_INTEGER
, end_in IN PLS_INTEGER
)
RETURN VARCHAR2
IS
BEGIN
RETURN ( SUBSTR (
string_in, start_in,
end_in - start_in + 1 ));
END;
With Oracle Database 12c, you can now define PL/SQL functions and procedures in the WITH clause
of a subquery and then use them as you would any other built-in or user-defined function. This
feature enables me to consolidate the BETWNSTR function and query shown above into a single
statement:
**12c**
WITH
FUNCTION betwnstr (
string_in IN VARCHAR2,
start_in IN PLS_INTEGER,
end_in IN PLS_INTEGER)
RETURN VARCHAR2
IS
BEGIN
RETURN (SUBSTR (
string_in,
start_in,
end_in - start_in + 1));
END;
* The classic workaround to this limitation has been to define a function in the package and then call
the function:
Step1:
Package created.
Step2:
OUTPUT:
SELECT pkg.year_number FROM employees
ERROR at line 1:
ORA-06553: PLS-221: 'YEAR_NUMBER' is not
a procedure or is undefined
The classic workaround to this limitation has been to define a function in the package and then call
the function:
Step4:
YEAR_NUMBER
———————————
2013
That’s a lot of code and effort simply to be able to reference the constant’s value in a SQL statement.
And, with Oracle Database 12c, it is no longer necessary. I can revert to and recompile the original
pkg, containing just a single constant named year_number in the package specification, and create a
function in the WITH clause:
WITH
FUNCTION year_number
RETURN INTEGER
IS
BEGIN
RETURN pkg.year_number;
END;
SELECT year_number
FROM employees
WHERE employee_id = 13
Next, I create the specification of my “private” package. The package is private in the sense that I
want to make sure that it can be invoked only from within the public package (public_pkg). So I
add the ACCESSIBLE_BY clause:
PROCEDURE do_that;
END;
/
Now it’s time to implement the package bodies. The public_pkg.do_only_this procedure calls the
private_pkg subprograms:
I can now run the public package’s procedure without any problem:
BEGIN
public_pkg.do_only_this;
END;
/
But if I try to call a subprogram in the private package in an anonymous block, I see this error:
BEGIN
private_pkg.do_this;
END;
/
OUTPUT:
ERROR at line 2:
ORA-06550: line 2, column 1:
PLS-00904: insufficient privilege to
access object PRIVATE_PKG
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
And the same error occurs if I try to compile a program unit that tries to call a subprogram in the
private package:
LINE/COL ERROR
———————— ——————————————————————————
4/4 PL/SQL: Statement ignored
4/4 PLS-00904: insufficient
privilege to access object
PRIVATE_PKG
As the “PLS” error indicates, this issue is caught at compilation time. There is no runtime
performance hit for using this feature.
Before Oracle Database 12c, a definer’s rights program unit (defined with the AUTHID DEFINER or no
AUTHID clause) always executed with the privileges of the definer of that unit. An invoker’s rights
program unit (defined with the AUTHID CURRENT_USER clause) always executed with the privileges
of the invoker of that unit.
A consequence of these two distinct AUTHID settings is that program units that need to be executed
by all users would have to be created as definer’s rights units. The program units would then execute
with all the privileges of the definer, which might not be optimal from a security standpoint.
As of Oracle Database 12c, you can grant roles to PL/SQL packages and schema-level procedures and
functions. Role-based privileges for program units enable developers to fine-tune the privileges
available to the invoker of a program unit.
You can now define a program unit as having invoker’s rights and then complement the invoker’s
privileges with specific, limited privileges granted through the role.
Let’s walk through an example that shows how to grant roles to program units and the impact it has.
Suppose that the HR schema contains the departments and employees tables, defined and populated
with data as follows:
Step1:
Step2:
BEGIN
INSERT INTO departments
VALUES (10, 'IT', 'Y');
COMMIT;
END;
/
Step3:
Step4:
BEGIN
DELETE FROM employees;
COMMIT;
END;
/
Step1:
SET SERVEROUTPUT ON
DECLARE
l_sql VARCHAR2(32767);
l_boolean BOOLEAN := TRUE;
l_result VARCHAR2(10);
BEGIN
l_sql := 'SELECT boolean_test(:l_boolean) INTO :l_result FROM
dual';
EXECUTE IMMEDIATE l_sql INTO l_result USING l_boolean;
DBMS_OUTPUT.put_line('l_result=' || l_result);
END;
Step2:
OUTPUT:
/
l_result=TRUE
Notice what happens if we try to substitute the bound BOOLEAN type for a BOOLEAN literal.
DECLARE
l_sql VARCHAR2(32767);
l_result VARCHAR2(10);
BEGIN
l_sql := 'SELECT boolean_test(TRUE) INTO :l_result FROM dual';
EXECUTE IMMEDIATE l_sql INTO l_result;
OUTPUT:
ERROR at line 1:
ORA-00904: "TRUE": invalid identifier
ORA-06512: at line 6
F. Record Types
The following code shows an example of binding record types in an anonymous blocked called from
dynamic SQL.
END;
/
END;
/
SET SERVEROUTPUT ON
DECLARE
l_sql VARCHAR2(32767);
l_record test_pkg.rec_type;
BEGIN
l_sql := 'BEGIN test_pkg.record_test(:l_record); END;';
OUTPUT:
l_record.id = 1
l_record.description = ONE
G. Collections
The following code shows an asociative array being bound. Currently, only associative arrays using
INDEX BY PLS_INTEGER can be bound in this way, not those using INDEX BY VARCHAR2
END;
/
RETURN p_collection.COUNT;
END;
END;
/
SET SERVEROUTPUT ON
DECLARE
l_sql VARCHAR2(32767);
l_collection test_pkg.collection_type;
l_result NUMBER;
BEGIN
l_sql := 'SELECT
test_pkg.display_collection_contents(:l_collection) INTO :l_result
FROM dual';
EXECUTE IMMEDIATE l_sql INTO l_result USING l_collection;
DBMS_OUTPUT.put_line('l_result=' || l_result);
END;
/
OUTPUT:
1 : ONE
2 : TWO
3 : THREE
l_result=3
The following example is similar to the previous associative array example, but it uses a nested table
type.
END;
/
RETURN p_collection.COUNT;
SET SERVEROUTPUT ON
DECLARE
l_sql VARCHAR2(32767);
l_collection test_pkg.collection_type;
l_result NUMBER;
BEGIN
l_collection := test_pkg.collection_type('ONE', 'TWO', 'THREE');
l_sql := 'SELECT
test_pkg.display_collection_contents(:l_collection) INTO :l_result
FROM dual';
EXECUTE IMMEDIATE l_sql INTO l_result USING l_collection;
DBMS_OUTPUT.put_line('l_result=' || l_result);
END;
/
OUTPUT:
1 : ONE
2 : TWO
3 : THREE
l_result=3
The VARRAY example below is very similar to that for nested tables.
END;
/
RETURN p_collection.COUNT;
END;
END;
/
SET SERVEROUTPUT ON
DECLARE
l_sql VARCHAR2(32767);
l_collection test_pkg.collection_type;
l_result NUMBER;
BEGIN
l_collection := test_pkg.collection_type('ONE', 'TWO', 'THREE');
l_sql := 'SELECT
test_pkg.display_collection_contents(:l_collection) INTO :l_result
FROM dual';
EXECUTE IMMEDIATE l_sql INTO l_result USING l_collection;
DBMS_OUTPUT.put_line('l_result=' || l_result);
END;
/
OUTPUT:
1 : ONE
2 : TWO
3 : THREE
l_result=3
H. TABLE Operator
The following code defines a pipelined table function that accepts a PL/SQL collection and pipes its
contents out a rows, so it can be queried using the TABLE operator.
END;
/
RETURN;
END;
END;
/
SET SERVEROUTPUT ON
DECLARE
l_sql VARCHAR2(32767);
l_collection test_pkg.collection_type;
l_result NUMBER;
BEGIN
l_collection := test_pkg.collection_type('ONE', 'TWO', 'THREE');
OUTPUT:
l_result=3