You are on page 1of 14

i.

A REF Cursor is a datatype that holds a cursor value in the same way that a
VARCHAR2 variable will hold a string value.
A REF Cursor can be opened on the server and passed to the client as a unit rather than fetching
one row at a time. One can use a Ref Cursor as target of an assignment, and it can be passed as
parameter to other program units. Ref Cursors are opened with an OPEN FOR statement. In most
other ways they behave similar to normal cursors.
ii. With the REF_CURSOR you can return a recordset/cursor from a stored procedure.

iii. Ref cussor variable can be associated with different query at the run time.

iv. Consider a situation when you want a flexibility to run any query that wiil be decided
during the run time and it may result in getting any type of data due to the result of
dynamic query we can use the reference cursor.
Example
Create a function that opens a cursor and returns a reference to it:
CREATE OR REPLACE FUNCTION f RETURN SYS_REFCURSOR
AS
c SYS_REFCURSOR;
BEGIN
OPEN c FOR select * from dual;
RETURN c;
END;
/
Call the above function and fetch all rows from the cursor it returns:
set serveroutput on
DECLARE
c SYS_REFCURSOR;
v VARCHAR2(1);
BEGIN
c := f(); -- Get ref cursor from function
LOOP
FETCH c into v;
EXIT WHEN c%NOTFOUND;
dbms_output.put_line('Value from cursor: '||v);
END LOOP;
END;
/





How to Use the SYS_REFCURSOR and REF CURSOR in Oracle Packages and
Procedures
SYS_REFCURSOR is a built-in REF CURSOR type that allows any result set to
be associated with it and can be used in 9i or higher. SYS_REFCURSOR can
be used to:
Delcare a cursor variable in an Oracle stored procedure/function;
Pass cursors from and to an Oracle stored procedure/function.
















PL/SQL Recursive Functions
We have seen that a program or subprogram may call another subprogram. When a subprogram calls itself, it is
referred to as a recursive call and the process is known as recursion.
To illustrate the concept, let us calculate the factorial of a number. Factorial of a number n is defined as:
n! = n*(n-1)!
= n*(n-1)*(n-2)!
...
= n*(n-1)*(n-2)*(n-3)... 1
The following program calculates the factorial of a given number by calling itself recursively:
DECLARE
num number;
factorial number;
FUNCTION fact(x number)
RETURN number
IS
f number;
BEGIN
IF x=0 THEN
f := 1;
ELSE
f := x * fact(x-1);
END IF;
RETURN f;
END;
BEGIN
num:= 6;
factorial := fact(num);
dbms_output.put_line(' Factorial '|| num || ' is ' || factorial);
END;
/
When the above code is executed at SQL prompt, it produces the following result:
Factorial 6 is 720
PL/SQL procedure successfully completed.
PL/SQL program units include:
Anonymous Blocks
Stored Program Units (Procedures, Functions, and Packages)
Triggers
Anonymous Blocks
An anonymous block is a PL/SQL program unit that has no name. An anonymous block
consists of an optional declarative part, an executable part, and one or more optional
exception handlers.
The declarative part declares PL/SQL variables, exceptions, and cursors. The executable
part contains PL/SQL code and SQL statements, and can contain nested blocks.
Exception handlers contain code that is called when the exception is raised, either as a
predefined PL/SQL exception (such as NO_DATA_FOUND or ZERO_DIVIDE) or as an
exception that you define.
The following short example of a PL/SQL anonymous block prints the names of all
employees in department 20 in the hr.employees table by using the
DBMS_OUTPUT package:
DECLARE
Last_name VARCHAR2(10);
Cursor c1 IS SELECT last_name
FROM employees
WHERE department_id = 20;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO Last_name;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(Last_name);
END LOOP;
END;
/














Stored Program Units (Procedures, Functions, and Packages)
A stored procedure, function, or package is a PL/SQL program unit that:
Has a name.
Can take parameters, and can return values.
Is stored in the data dictionary.
Can be called by many users.

PROCEDURE Get_emp_names (Dept_num IN NUMBER) IS
Emp_name VARCHAR2(10);
CURSOR c1 (Depno NUMBER) IS
SELECT Ename FROM Emp_tab
WHERE deptno = Depno;
BEGIN
OPEN c1(Dept_num);
LOOP
FETCH c1 INTO Emp_name;
EXIT WHEN C1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(Emp_name);
END LOOP;
CLOSE c1;
END;






















Overview of Bulk Binds
Oracle Database uses two engines to run PL/SQL blocks and subprograms. The PL/SQL
engine runs procedural statements, while the SQL engine runs SQL statements. During
execution, every SQL statement causes a context switch between the two engines,
resulting in performance overhead.
Performance can be improved substantially by minimizing the number of context
switches required to run a particular block or subprogram. When a SQL statement runs
inside a loop that uses collection elements as bind variables, the large number of
context switches required by the block can cause poor performance. Collections include
the following:
Varrays
Nested tables
Index-by tables
Host arrays
Binding is the assignment of values to PL/SQL variables in SQL statements. Bulk
binding is binding an entire collection at once. Bulk binds pass the entire collection
back and forth between the two engines in a single operation.
Typically, using bulk binds improves performance for SQL statements that affect four or
more database rows. The more rows affected by a SQL statement, the greater the
performance gain from bulk binds.

When to Use Bulk Binds
If you have scenarios like these in your applications, consider using bulk binds to
improve performance.
DML Statements that Reference Collections
The FORALL keyword can improve the performance of INSERT, UPDATE, or DELETE
statements that reference collection elements.
For example, the following PL/SQL block increases the salary for employees whose
manager's ID number is 7902, 7698, or 7839, both with and without using bulk binds:
DECLARE
TYPE Numlist IS VARRAY (100) OF NUMBER;
Id NUMLIST := NUMLIST(7902, 7698, 7839);
BEGIN

-- Efficient method, using a bulk bind
FORALL i IN Id.FIRST..Id.LAST -- bulk-bind the VARRAY
UPDATE Emp_tab SET Sal = 1.1 * Sal
WHERE Mgr = Id(i);

-- Slower method, running the UPDATE statements within a regular loop
FOR i IN Id.FIRST..Id.LAST LOOP
UPDATE Emp_tab SET Sal = 1.1 * Sal
WHERE Mgr = Id(i);
END LOOP;
END;


SELECT Statements that Reference Collections
The BULK COLLECT INTO clause can improve the performance of queries that
reference collections.
For example, the following PL/SQL block queries multiple values into PL/SQL tables,
both with and without bulk binds:
-- Find all employees whose manager's ID number is 7698.
DECLARE
TYPE Var_tab IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;
Empno VAR_TAB;
Ename VAR_TAB;
Counter NUMBER;
CURSOR C IS
SELECT Empno, Ename FROM Emp_tab WHERE Mgr = 7698;
BEGIN

-- Efficient method, using a bulk bind
SELECT Empno, Ename BULK COLLECT INTO Empno, Ename
FROM Emp_Tab WHERE Mgr = 7698;

-- Slower method, assigning each collection element within a loop.

counter := 1;
FOR rec IN C LOOP
Empno(Counter) := rec.Empno;
Ename(Counter) := rec.Ename;
Counter := Counter + 1;
END LOOP;
END;

You can use BULK COLLECT INTO with tables of scalar values, or tables of %TYPE
values.
Without the bulk bind, PL/SQL sends a SQL statement to the SQL engine for each
employee that is selected, leading to context switches that hurt performance.
FOR Loops that Reference Collections and the Returning Into Clause
You can use the FORALL keyword along with the BULK COLLECT INTO keywords to
improve the performance of FOR loops that reference collections and return DML.
For example, the following PL/SQL block updates the Emp_tab table by computing
bonuses for a collection of employees; then it returns the bonuses in a column called
Bonlist. The actions are performed both with and without using bulk binds:
DECLARE
TYPE Emplist IS VARRAY(100) OF NUMBER;
Empids EMPLIST := EMPLIST(7369, 7499, 7521, 7566, 7654, 7698);
TYPE Bonlist IS TABLE OF Emp_tab.sal%TYPE;
Bonlist_inst BONLIST;
BEGIN
Bonlist_inst := BONLIST(1,2,3,4,5);

FORALL i IN Empids.FIRST..empIDs.LAST
UPDATE Emp_tab SET Bonus = 0.1 * Sal
WHERE Empno = Empids(i)
RETURNING Sal BULK COLLECT INTO Bonlist;

FOR i IN Empids.FIRST..Empids.LAST LOOP
UPDATE Emp_tab Set Bonus = 0.1 * sal
WHERE Empno = Empids(i)
RETURNING Sal INTO BONLIST(i);
END LOOP;
END;

Without the bulk bind, PL/SQL sends a SQL statement to the SQL engine for each
employee that is updated, leading to context switches that hurt performance.










Passing Large Data Structures with the NOCOPY
Compiler Hint
Suppose a subprogram declares an IN parameter, an OUT parameter, and an IN OUT parameter.
When you call the subprogram, the IN parameter is passed by reference. That is, a pointer to the
IN actual parameter is passed to the corresponding formal parameter. So, both parameters
reference the same memory location, which holds the value of the actual parameter.
By default, the OUT and IN OUT parameters are passed by value. That is, the value of the IN OUT
actual parameter is copied into the corresponding formal parameter. Then, if the subprogram
exits normally, the values assigned to the OUT and IN OUT formal parameters are copied into the
corresponding actual parameters.
When the parameters hold large data structures such as collections, records, and instances of
object types, all this copying slows down execution and uses up memory. To prevent that, you
can specify the NOCOPY hint, which allows the PL/SQL compiler to pass OUT and IN OUT
parameters by reference.
In the following example, you ask the compiler to pass IN OUT parameter my_staff by reference
instead of by value:
DECLARE
TYPE Staff IS VARRAY(200) OF Employee;
PROCEDURE reorganize (my_staff IN OUT NOCOPY Staff) IS ...

Remember, NOCOPY is a hint, not a directive. So, the compiler might pass my_staff by value
despite your request. Usually, however, NOCOPY succeeds. So, it can benefit any PL/SQL
application that passes around large data structures.
In the example below, 25000 records are loaded into a local nested table, which is passed to two
local procedures that do nothing but execute NULL statements. However, a call to one procedure
takes 21 seconds because of all the copying. With NOCOPY, a call to the other procedure takes
much less than 1 second.
SQL> SET SERVEROUTPUT ON
SQL> GET test.sql
1 DECLARE
2 TYPE EmpTabTyp IS TABLE OF emp%ROWTYPE;
3 emp_tab EmpTabTyp := EmpTabTyp(NULL); -- initialize
4 t1 NUMBER(5);
5 t2 NUMBER(5);
6 t3 NUMBER(5);
7 PROCEDURE get_time (t OUT NUMBER) IS
8 BEGIN SELECT TO_CHAR(SYSDATE,'SSSSS') INTO t FROM dual; END;
9 PROCEDURE do_nothing1 (tab IN OUT EmpTabTyp) IS
10 BEGIN NULL; END;
11 PROCEDURE do_nothing2 (tab IN OUT NOCOPY EmpTabTyp) IS
12 BEGIN NULL; END;
13 BEGIN
14 SELECT * INTO emp_tab(1) FROM emp WHERE empno = 7788;
15 emp_tab.EXTEND(24999, 1); -- copy element 1 into 2..25000
16 get_time(t1);
17 do_nothing1(emp_tab); -- pass IN OUT parameter
18 get_time(t2);
19 do_nothing2(emp_tab); -- pass IN OUT NOCOPY parameter
20 get_time(t3);
21 dbms_output.put_line('Call Duration (secs)');
22 dbms_output.put_line('--------------------');
23 dbms_output.put_line('Just IN OUT: ' || TO_CHAR(t2 - t1));
24 dbms_output.put_line('With NOCOPY: ' || TO_CHAR(t3 - t2));
25* END;
SQL> /
Call Duration (secs)
--------------------
Just IN OUT: 21
With NOCOPY: 0

















Submit a concurrent request from Unix
submit a concurrent request to run any concurrent program by running the CONCSUB
program with the following syntax:
CONCSUB <APPS username>/<APPS password> \
<responsibility application short name> \
<responsibility name> \
<username> \
[WAIT=N|Y|<n seconds>] \
CONCURRENT \
<program application short name> \
<program name> \
[PROGRAM_NAME=<description>] \
NLS_LANGUAGE - R12 onwards only \
NLS_TERRITORY - R12 onwards only
[ORG_ID=<#>] - R12 onwards only
[REPEAT_TIME=<resubmission time>] \
[REPEAT_INTERVAL= <number>] \
[REPEAT_INTERVAL_UNIT=< resubmission unit>] \
[REPEAT_INTERVAL_TYPE=< resubmission type>] \
[REPEAT_END=<resubmission end date and time>] \
[START=<date>] \
[IMPLICIT=< type of concurrent request> \
[<parameter 1> ... <parameter n>]
Parameters
The following entries explain the required and optional parameters for submitting a
concurrent program with CONCSUB. Default values are listed to the right.
<username/password> Required. The ORACLE username and password that provides
access to the data that the program uses.

<responsibility application short name> Required. The application short name of the
responsibility whose concurrent processing options to be used.

<responsibility name> Required. The name of the responsibility. If the name of the
responsibility includes spaces, enclose that name in double quotes.

<username> Required. The uppercase username of the application user whose concurrent
processing options to use.

<WAIT> Optional. A flag that indicates whether to wait for the submitted request to complete.
If one leaves this parameter out, the default value of N makes CONCSUB return to the
operating system prompt without waiting for the request to complete.
Set WAIT=Y to have CONCSUB check the request status every 60 seconds and returns to the
operating system prompt when the request is completed. One can also enter an integer value
for a number of seconds, as in WAIT=30, for CONCSUB to check for request completion every
<number> seconds.

Attention: Using WAIT=Y or WAIT=<number> requires that the request completes before
CONCSUB returns to the operating system. If the concurrent manager is down, the CONCSUB
process waits indefinitely until the concurrent manager is started and the request completes.

<CONCURRENT> Required. A flag that separates the program specific parameters from the
operating system parameters.

<program application short name> Required. The application short name of the
concurrent program.

<program name> Required. The uppercase name of the program. It must be the short name
that was enter in the Concurrent Programs window when defining a concurrent program.

<PROGRAM_NAME> Optional. A descriptive name for your program. The program field on
the View Requests form displays this as the user friendly program name. The concurrent
program short name passed to CONCSUB is often hard for end users to understand, so the
PROGRAM_NAME parameter allows one to pass a more easily remembered name for a
concurrent program. If one does not specify a PROGRAM_NAME, the View Requests form
displays the user friendly program name specified in the Concurrent Programs window.
One may also use the PROGRAM_NAME parameter to indicate the batch that your request
processes for programs that process a set of data, where there could be several requests for a
given program that are active at the same time.

<ORG_ID> Optional. Introduced in R12, set to org id required for the report to be run with.

<REPEAT TIME> Optional. The time of day to resubmit the request. The format for the time
is HH24:MI or HH24:MI:SS. For example, REPEAT_TIME=14:30 resubmits the request daily at
2:30 p.m.

Attention: Do not use REPEAT_TIME with other resubmission parameters except for the
optional parameters REPEAT_END and START.

<REPEAT_INTERVAL> Optional. The interval between resubmission (a positive integer or
real number). Use this parameter along with REPEAT_INTERVAL_UNIT to specify the time
between resubmissions.

<REPEAT_INTERVAL_UNIT> Optional. The unit of time used for the interval between
resubmissions. The available units are MINUTES, HOURS, DAYS or MONTHS. Use this
parameter along with REPEAT_INTERVAL to specify the time between resubmissions. For
example, setting REPEAT_INTERVAL=12 and REPEAT_INTERVAL_UNIT=HOURS resubmits the
request every twelve hours. The default value is DAYS.

Attention: Do not use REPEAT_INTERVAL and REPEAT_INTERVAL_UNIT with REPEAT_TIME.

<REPEAT_INTERVAL_TYPE> Optional. Whether to time the resubmission interval from the
requested start time of the request or from its completion. Set this parameter either to START
or END. The default value is START.

Attention: Use REPEAT_INTERVAL_TYPE only if one uses REPEAT_INTERVAL.

<REPEAT_END> Optional. The date and time to stop resubmitting the concurrent request.
Use one of the following for the format of the end date:

DDMONRR HH24:MI:SS (as in 07APR02 18:32:05)
or
DDMONRRRR HH24:MI:SS (as in 07APR2002 18:32:05)
Note that because this date format includes a space, one must enclose the date in double
quotation marks and single quotation marks. One can also specify just the date:
DDMONRR
or
DDMONRRRR

<NLS_LANGUAGE> Optional. The NLS language for the request. (LANGUAGE='"SIMPLIFIED
CHINESE"' \)

<NLS_TERRITORY> Optional. The NLS territory for the request. (TERRITORY=CHINA \)

<START> Optional. A start date and time for the program in this format:
DDMONRR HH24:MI:SS (as in 07APR02 18:32:05)
Because this date format includes a space, one must enclose the date in double quotation
marks and single quotation marks. If one does not specify a start time, the program submits
immediately and is processed by the next available concurrent manager. The default value is
the current time.

<IMPLICIT> Optional. Whether to show this concurrent request on the View Requests form.
Specify NO, YES, ERROR or WARNING. The value IMPLICIT=NO allows the request to appear
on the View Request form. The default value is NO.
The value IMPLICIT=YES means that only the System Administrators privileged View
Concurrent Requests form displays this request. Use this value if the request is not interesting
to the user.
Specify IMPLICIT=ERROR or IMPLICIT=WARNING, respectively, if one wants the request to
appear only if it fails or completes with warnings.

<REPEAT_DAYS> Optional. The number of days after which to repeat the concurrent
request, calculated from the last requested start date. The number can be a positive integer or
real number. For example,
REPEAT_DAYS=1.5 resubmits the request every 36 hours.

Attention: Do not use REPEAT_DAYS with other resubmission parameters except for the
optional parameters REPEAT_END and START.
Suggestion: REPEAT_DAYS will become obsolete in a future release. One may therefore want to
use REPEAT_INTERVAL, REPEAT_INTERVAL_TYPE and REPEAT_INTERVAL_UNIT instead of
REPEAT_DAYS.

<parameter 1> ...<parameter n> Optional. The program specific parameters. If a parameter
includes spaces, enclose that parameter in double quotes, then in single quotes. If a parameter
contains a double quotation mark as part of the argument, precede that mark with a backslash
[\].

You might also like