Subprogram Parameters
If a subprogram has parameters, their values can differ for each invocation.
Topics
Formal and Actual Subprogram Parameters
If you want a subprogram to have parameters, declare formal parameters in the subprogram heading. In each formal parameter declaration, specify the name and data type of the parameter, and (optionally) its mode and default value. In the execution part of the subprogram, reference the formal parameters by their names.
When invoking the subprogram, specify the actual parameters whose values are to be assigned to the formal parameters. Corresponding actual and formal parameters must have compatible data types.
Note:
You can declare a formal parameter of a constrained subtype, like this:
DECLARE SUBTYPE n1 IS NUMBER(1); SUBTYPE v1 IS VARCHAR2(1); PROCEDURE p (n n1, v v1) IS ...
But you cannot include a constraint in a formal parameter declaration, like this:
DECLARE PROCEDURE p (n NUMBER(1), v VARCHAR2(1)) IS ...
Tip:
To avoid confusion, use different names for formal and actual parameters.
Note:
-
Actual parameters (including default values of formal parameters) can be evaluated in any order. If a program determines order of evaluation, then at the point where the program does so, its behavior is undefined.
-
You cannot use LOB parameters in a server-to-server remote procedure call (RPC).
In Example 9-9, the procedure has formal parameters emp_id
and amount
. In the first procedure invocation, the corresponding actual parameters are emp_num
and bonus
, whose value are 120 and 100, respectively. In the second procedure invocation, the actual parameters are emp_num
and merit
+ bonus
, whose value are 120 and 150, respectively.
Topics:
See Also:
-
"Formal Parameter Declaration" for the syntax and semantics of a formal parameter declaration
-
"function_call ::=" and "function_call" for the syntax and semantics of a function invocation
-
"procedure_call ::=" and "procedure" for the syntax and semantics of a procedure invocation
Example 9-9 Formal Parameters and Actual Parameters
DECLARE emp_num NUMBER(6) := 120; bonus NUMBER(6) := 100; merit NUMBER(4) := 50; PROCEDURE raise_salary ( emp_id NUMBER, -- formal parameter amount NUMBER -- formal parameter ) IS BEGIN UPDATE employees SET salary = salary + amount -- reference to formal parameter WHERE employee_id = emp_id; -- reference to formal parameter END raise_salary; BEGIN raise_salary(emp_num, bonus); -- actual parameters /* raise_salary runs this statement: UPDATE employees SET salary = salary + 100 WHERE employee_id = 120; */ raise_salary(emp_num, merit + bonus); -- actual parameters /* raise_salary runs this statement: UPDATE employees SET salary = salary + 150 WHERE employee_id = 120; */ END; /
Formal Parameters of Constrained Subtypes
If the data type of a formal parameter is a constrained subtype, then:
-
If the subtype has the
NOT
NULL
constraint, then the actual parameter inherits it. -
If the subtype has the base type
VARCHAR2
, then the actual parameter does not inherit the size of the subtype. -
If the subtype has a numeric base type, then the actual parameter inherits the range of the subtype, but not the precision or scale.
Note:
In a function, the clause RETURN
datatype
declares a hidden formal parameter and the statement RETURN
value
specifies the corresponding actual parameter. Therefore, if datatype
is a constrained data type, then the preceding rules apply to value
(see Example 9-11).
Example 9-10 shows that an actual subprogram parameter inherits the NOT
NULL
constraint but not the size of a VARCHAR2
subtype.
As PL/SQL Predefined Data Types shows, PL/SQL has many predefined data types that are constrained subtypes of other data types. For example, INTEGER
is a constrained subtype of NUMBER
:
SUBTYPE INTEGER IS NUMBER(38,0);
In Example 9-11, the function has both an INTEGER
formal parameter and an INTEGER
return type. The anonymous block invokes the function with an actual parameter that is not an integer. Because the actual parameter inherits the range but not the precision and scale of INTEGER
, and the actual parameter is in the INTEGER
range, the invocation succeeds. For the same reason, the RETURN
statement succeeds in returning the noninteger value.
In Example 9-12, the function implicitly converts its formal parameter to the constrained subtype INTEGER
before returning it.
See Also:
"Constrained Subtypes" for general information about constrained subtypes
Example 9-10 Actual Parameter Inherits Only NOT NULL from Subtype
DECLARE SUBTYPE License IS VARCHAR2(7) NOT NULL; n License := 'DLLLDDD'; PROCEDURE p (x License) IS BEGIN DBMS_OUTPUT.PUT_LINE(x); END; BEGIN p('1ABC123456789'); -- Succeeds; size is not inherited p(NULL); -- Raises error; NOT NULL is inherited END; /
Result:
p(NULL); -- Raises error; NOT NULL is inherited * ERROR at line 12: ORA-06550: line 12, column 5: PLS-00567: cannot pass NULL to a NOT NULL constrained formal parameter ORA-06550: line 12, column 3: PL/SQL: Statement ignored
Example 9-11 Actual Parameter and Return Value Inherit Only Range From Subtype
DECLARE
FUNCTION test (p INTEGER) RETURN INTEGER IS
BEGIN
DBMS_OUTPUT.PUT_LINE('p = ' || p);
RETURN p;
END test;
BEGIN
DBMS_OUTPUT.PUT_LINE('test(p) = ' || test(0.66));
END;
/
Result:
p = .66 test(p) = .66 PL/SQL procedure successfully completed.
Example 9-12 Function Implicitly Converts Formal Parameter to Constrained Subtype
DECLARE FUNCTION test (p NUMBER) RETURN NUMBER IS q INTEGER := p; -- Implicitly converts p to INTEGER BEGIN DBMS_OUTPUT.PUT_LINE('p = ' || q); -- Display q, not p RETURN q; -- Return q, not p END test; BEGIN DBMS_OUTPUT.PUT_LINE('test(p) = ' || test(0.66)); END; /
Result:
p = 1 test(p) = 1 PL/SQL procedure successfully completed.
Subprogram Parameter Passing Methods
The PL/SQL compiler has two ways of passing an actual parameter to a subprogram:
-
By reference
The compiler passes the subprogram a pointer to the actual parameter. The actual and formal parameters refer to the same memory location.
-
By value
The compiler assigns the value of the actual parameter to the corresponding formal parameter. The actual and formal parameters refer to different memory locations.
If necessary, the compiler implicitly converts the data type of the actual parameter to the data type of the formal parameter. For information about implicit data conversion, see Oracle Database SQL Language Reference.
Tip:
Avoid implicit data conversion (for the reasons in Oracle Database SQL Language Reference), in either of these ways:
-
Declare the variables that you intend to use as actual parameters with the same data types as their corresponding formal parameters (as in the declaration of variable
x
in Example 9-13). -
Explicitly convert actual parameters to the data types of their corresponding formal parameters, using the SQL conversion functions described in Oracle Database SQL Language Reference (as in the third invocation of the procedure in Example 9-13).
-
In Example 9-13, the procedure p
has one parameter, n
, which is passed by value. The anonymous block invokes p
three times, avoiding implicit conversion twice.
The method by which the compiler passes a specific actual parameter depends on its mode, as explained in "Subprogram Parameter Modes".
Example 9-13 Avoiding Implicit Conversion of Actual Parameters
CREATE OR REPLACE PROCEDURE p ( n NUMBER ) AUTHID DEFINER IS BEGIN NULL; END; / DECLARE x NUMBER := 1; y VARCHAR2(1) := '1'; BEGIN p(x); -- No conversion needed p(y); -- z implicitly converted from VARCHAR2 to NUMBER p(TO_NUMBER(y)); -- z explicitly converted from VARCHAR2 to NUMBER END; /
Subprogram Parameter Modes
The mode of a formal parameter determines its behavior.
Table 9-1 summarizes and compares the characteristics of the subprogram parameter modes.
Table 9-1 PL/SQL Subprogram Parameter Modes
Parameter Mode | Is Default? | Role |
---|---|---|
IN |
Default mode |
Passes a value to the subprogram. |
OUT |
Must be specified. |
Returns a value to the invoker. |
IN OUT |
Must be specified. |
Passes an initial value to the subprogram and returns an updated value to the invoker. |
Table 9-2 PL/SQL Subprogram Parameter Modes Characteristics
Parameter Mode | Formal Parameter | Actual Parameter | Passed by Reference ? |
---|---|---|---|
IN |
Formal parameter acts like a constant: When the subprogram begins, its value is that of either its actual parameter or default value, and the subprogram cannot change this value. |
Actual parameter can be a constant, initialized variable, literal, or expression. |
Actual parameter is passed by reference. |
OUT |
Formal parameter is initialized to the default value of its type. The default value of the type is When the subprogram begins, the formal parameter has its initial value regardless of the value of its actual parameter. Oracle recommends that the subprogram assign a value to the formal parameter. |
If the default value of the formal parameter type is |
By default, actual parameter is passed by value; if you specify |
IN OUT |
Formal parameter acts like an initialized variable: When the subprogram begins, its value is that of its actual parameter. Oracle recommends that the subprogram update its value. |
Actual parameter must be a variable (typically, it is a string buffer or numeric accumulator). |
By default, actual parameter is passed by value (in both directions); if you specify |
Tip:
Do not use OUT
and IN
OUT
for function parameters. Ideally, a function takes zero or more parameters and returns a single value. A function with IN
OUT
parameters returns multiple values and has side effects.
Note:
The specifications of many packages and types that Oracle Database supplies declare formal parameters with this notation:
i1 IN VARCHAR2 CHARACTER SET ANY_CS i2 IN VARCHAR2 CHARACTER SET i1%CHARSET
Do not use this notation when declaring your own formal or actual parameters. It is reserved for Oracle implementation of the supplied packages types.
Regardless of how an OUT
or IN
OUT
parameter is passed:
-
If the subprogram exits successfully, then the value of the actual parameter is the final value assigned to the formal parameter. (The formal parameter is assigned at least one value—the initial value.)
-
If the subprogram ends with an exception, then the value of the actual parameter is undefined.
-
Formal
OUT
andIN
OUT
parameters can be returned in any order. In this example, the final values ofx
andy
are undefined:CREATE OR REPLACE PROCEDURE p (x OUT INTEGER, y OUT INTEGER) AS BEGIN x := 17; y := 93; END; /
When an OUT
or IN
OUT
parameter is passed by reference, the actual and formal parameters refer to the same memory location. Therefore, if the subprogram changes the value of the formal parameter, the change shows immediately in the actual parameter (see "Subprogram Parameter Aliasing with Parameters Passed by Reference").
In Example 9-14, the procedure p
has two IN
parameters, one OUT
parameter, and one IN
OUT
parameter. The OUT
and IN
OUT
parameters are passed by value (the default). The anonymous block invokes p
twice, with different actual parameters. Before each invocation, the anonymous block prints the values of the actual parameters. The procedure p
prints the initial values of its formal parameters. After each invocation, the anonymous block prints the values of the actual parameters again.
In Example 9-15, the anonymous block invokes procedure p
(from Example 9-14) with an actual parameter that causes p
to raise the predefined exception ZERO_DIVIDE
, which p
does not handle. The exception propagates to the anonymous block, which handles ZERO_DIVIDE
and shows that the actual parameters for the IN
and IN
OUT
parameters of p
have retained the values that they had before the invocation. (Exception propagation is explained in "Exception Propagation".)
In Example 9-16, the procedure p
has three OUT
formal parameters: x
, of a record type with a non-NULL
default value; y
, of a record type with no non-NULL
default value; and z
, which is not a record.
The corresponding actual parameters for x
, y
, and z
are r1
, r2
, and s
, respectively. s
is declared with an initial value. However, when p
is invoked, the value of s
is initialized to NULL
. The values of r1
and r2
are initialized to the default values of their record types, 'abcde'
and NULL
, respectively.
Example 9-14 Parameter Values Before, During, and After Procedure Invocation
CREATE OR REPLACE PROCEDURE p ( a PLS_INTEGER, -- IN by default b IN PLS_INTEGER, c OUT PLS_INTEGER, d IN OUT BINARY_FLOAT ) AUTHID DEFINER IS BEGIN -- Print values of parameters: DBMS_OUTPUT.PUT_LINE('Inside procedure p:'); DBMS_OUTPUT.PUT('IN a = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(a), 'NULL')); DBMS_OUTPUT.PUT('IN b = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(b), 'NULL')); DBMS_OUTPUT.PUT('OUT c = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(c), 'NULL')); DBMS_OUTPUT.PUT_LINE('IN OUT d = ' || TO_CHAR(d)); -- Can reference IN parameters a and b, -- but cannot assign values to them. c := a+10; -- Assign value to OUT parameter d := 10/b; -- Assign value to IN OUT parameter END; / DECLARE aa CONSTANT PLS_INTEGER := 1; bb PLS_INTEGER := 2; cc PLS_INTEGER := 3; dd BINARY_FLOAT := 4; ee PLS_INTEGER; ff BINARY_FLOAT := 5; BEGIN DBMS_OUTPUT.PUT_LINE('Before invoking procedure p:'); DBMS_OUTPUT.PUT('aa = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(aa), 'NULL')); DBMS_OUTPUT.PUT('bb = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(bb), 'NULL')); DBMS_OUTPUT.PUT('cc = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(cc), 'NULL')); DBMS_OUTPUT.PUT_LINE('dd = ' || TO_CHAR(dd)); p (aa, -- constant bb, -- initialized variable cc, -- initialized variable dd -- initialized variable ); DBMS_OUTPUT.PUT_LINE('After invoking procedure p:'); DBMS_OUTPUT.PUT('aa = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(aa), 'NULL')); DBMS_OUTPUT.PUT('bb = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(bb), 'NULL')); DBMS_OUTPUT.PUT('cc = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(cc), 'NULL')); DBMS_OUTPUT.PUT_LINE('dd = ' || TO_CHAR(dd)); DBMS_OUTPUT.PUT_LINE('Before invoking procedure p:'); DBMS_OUTPUT.PUT('ee = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(ee), 'NULL')); DBMS_OUTPUT.PUT_LINE('ff = ' || TO_CHAR(ff)); p (1, -- literal (bb+3)*4, -- expression ee, -- uninitialized variable ff -- initialized variable ); DBMS_OUTPUT.PUT_LINE('After invoking procedure p:'); DBMS_OUTPUT.PUT('ee = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(ee), 'NULL')); DBMS_OUTPUT.PUT_LINE('ff = ' || TO_CHAR(ff)); END; /
Result:
Before invoking procedure p: aa = 1 bb = 2 cc = 3 dd = 4.0E+000 Inside procedure p: IN a = 1 IN b = 2 OUT c = NULL IN OUT d = 4.0E+000 After invoking procedure p: aa = 1 bb = 2 cc = 11 dd = 5.0E+000 Before invoking procedure p: ee = NULL ff = 5.0E+000 Inside procedure p: IN a = 1 IN b = 20 OUT c = NULL IN OUT d = 5.0E+000 After invoking procedure p: ee = 11 ff = 5.0E-001 PL/SQL procedure successfully completed.
Example 9-15 OUT and IN OUT Parameter Values After Exception Handling
DECLARE j PLS_INTEGER := 10; k BINARY_FLOAT := 15; BEGIN DBMS_OUTPUT.PUT_LINE('Before invoking procedure p:'); DBMS_OUTPUT.PUT('j = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(j), 'NULL')); DBMS_OUTPUT.PUT_LINE('k = ' || TO_CHAR(k)); p(4, 0, j, k); -- causes p to exit with exception ZERO_DIVIDE EXCEPTION WHEN ZERO_DIVIDE THEN DBMS_OUTPUT.PUT_LINE('After invoking procedure p:'); DBMS_OUTPUT.PUT('j = '); DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(j), 'NULL')); DBMS_OUTPUT.PUT_LINE('k = ' || TO_CHAR(k)); END; /
Result:
Before invoking procedure p: j = 10 k = 1.5E+001 Inside procedure p: IN a = 4 IN b = 0 OUT c = NULL IN OUT d = 1.5E+001 After invoking procedure p: j = 10 k = 1.5E+001 PL/SQL procedure successfully completed.
Example 9-16 OUT Formal Parameter of Record Type with Non-NULL Default Value
CREATE OR REPLACE PACKAGE r_types AUTHID DEFINER IS TYPE r_type_1 IS RECORD (f VARCHAR2(5) := 'abcde'); TYPE r_type_2 IS RECORD (f VARCHAR2(5)); END; / CREATE OR REPLACE PROCEDURE p ( x OUT r_types.r_type_1, y OUT r_types.r_type_2, z OUT VARCHAR2) AUTHID CURRENT_USER IS BEGIN DBMS_OUTPUT.PUT_LINE('x.f is ' || NVL(x.f,'NULL')); DBMS_OUTPUT.PUT_LINE('y.f is ' || NVL(y.f,'NULL')); DBMS_OUTPUT.PUT_LINE('z is ' || NVL(z,'NULL')); END; / DECLARE r1 r_types.r_type_1; r2 r_types.r_type_2; s VARCHAR2(5) := 'fghij'; BEGIN p (r1, r2, s); END; /
Result:
x.f is abcde y.f is NULL z is NULL PL/SQL procedure successfully completed.
Subprogram Parameter Aliasing
Aliasing is having two different names for the same memory location. If a stored item is visible by more than one path, and you can change the item by one path, then you can see the change by all paths.
Subprogram parameter aliasing always occurs when the compiler passes an actual parameter by reference, and can also occur when a subprogram has cursor variable parameters.
Topics
Subprogram Parameter Aliasing with Parameters Passed by Reference
When the compiler passes an actual parameter by reference, the actual and formal parameters refer to the same memory location. Therefore, if the subprogram changes the value of the formal parameter, the change shows immediately in the actual parameter.
The compiler always passes IN
parameters by reference, but the resulting aliasing cannot cause problems, because subprograms cannot assign values to IN
parameters.
The compiler might pass an OUT
or IN
OUT
parameter by reference, if you specify NOCOPY
for that parameter. NOCOPY
is only a hint—each time the subprogram is invoked, the compiler decides, silently, whether to obey or ignore NOCOPY
. Therefore, aliasing can occur for one invocation but not another, making subprogram results indeterminate. For example:
-
If the actual parameter is a global variable, then an assignment to the formal parameter might show in the global parameter (see Example 9-17).
-
If the same variable is the actual parameter for two formal parameters, then an assignment to either formal parameter might show immediately in both formal parameters (see Example 9-18).
-
If the actual parameter is a package variable, then an assignment to either the formal parameter or the package variable might show immediately in both the formal parameter and the package variable.
-
If the subprogram is exited with an unhandled exception, then an assignment to the formal parameter might show in the actual parameter.
See Also:
"NOCOPY" for the cases in which the compiler always ignores NOCOPY
In Example 9-17, the procedure has an IN
OUT
NOCOPY
formal parameter, to which it assigns the value 'aardvark'
. The anonymous block assigns the value 'aardwolf'
to a global variable and then passes the global variable to the procedure. If the compiler obeys the NOCOPY
hint, then the final value of the global variable is 'aardvark'
. If the compiler ignores the NOCOPY
hint, then the final value of the global variable is 'aardwolf'
.
In Example 9-18, the procedure has an IN
parameter, an IN
OUT
parameter, and an IN
OUT
NOCOPY
parameter. The anonymous block invokes the procedure, using the same actual parameter, a global variable, for all three formal parameters. The procedure changes the value of the IN
OUT
parameter before it changes the value of the IN
OUT
NOCOPY
parameter. However, if the compiler obeys the NOCOPY
hint, then the latter change shows in the actual parameter immediately. The former change shows in the actual parameter after the procedure is exited successfully and control returns to the anonymous block.
Example 9-17 Aliasing from Global Variable as Actual Parameter
DECLARE
TYPE Definition IS RECORD (
word VARCHAR2(20),
meaning VARCHAR2(200)
);
TYPE Dictionary IS VARRAY(2000) OF Definition;
lexicon Dictionary := Dictionary(); -- global variable
PROCEDURE add_entry (
word_list IN OUT NOCOPY Dictionary -- formal NOCOPY parameter
) IS
BEGIN
word_list(1).word := 'aardvark';
END;
BEGIN
lexicon.EXTEND;
lexicon(1).word := 'aardwolf';
add_entry(lexicon); -- global variable is actual parameter
DBMS_OUTPUT.PUT_LINE(lexicon(1).word);
END;
/
Result:
aardvark
Example 9-18 Aliasing from Same Actual Parameter for Multiple Formal Parameters
DECLARE n NUMBER := 10; PROCEDURE p ( n1 IN NUMBER, n2 IN OUT NUMBER, n3 IN OUT NOCOPY NUMBER ) IS BEGIN n2 := 20; -- actual parameter is 20 only after procedure succeeds DBMS_OUTPUT.put_line(n1); -- actual parameter value is still 10 n3 := 30; -- might change actual parameter immediately DBMS_OUTPUT.put_line(n1); -- actual parameter value is either 10 or 30 END; BEGIN p(n, n, n); DBMS_OUTPUT.put_line(n); END; /
Result if the compiler obeys the NOCOPY
hint:
10 30 20
Result if the compiler ignores the NOCOPY
hint:
10 10 30
Subprogram Parameter Aliasing with Cursor Variable Parameters
Cursor variable parameters are pointers. Therefore, if a subprogram assigns one cursor variable parameter to another, they refer to the same memory location. This aliasing can have unintended results.
In Example 9-19, the procedure has two cursor variable parameters, emp_cv1
and emp_cv2
. The procedure opens emp_cv1
and assigns its value (which is a pointer) to emp_cv2
. Now emp_cv1
and emp_cv2
refer to the same memory location. When the procedure closes emp_cv1
, it also closes emp_cv2
. Therefore, when the procedure tries to fetch from emp_cv2
, PL/SQL raises an exception.
Example 9-19 Aliasing from Cursor Variable Subprogram Parameters
DECLARE TYPE EmpCurTyp IS REF CURSOR; c1 EmpCurTyp; c2 EmpCurTyp; PROCEDURE get_emp_data ( emp_cv1 IN OUT EmpCurTyp, emp_cv2 IN OUT EmpCurTyp ) IS emp_rec employees%ROWTYPE; BEGIN OPEN emp_cv1 FOR SELECT * FROM employees; emp_cv2 := emp_cv1; -- now both variables refer to same location FETCH emp_cv1 INTO emp_rec; -- fetches first row of employees FETCH emp_cv1 INTO emp_rec; -- fetches second row of employees FETCH emp_cv2 INTO emp_rec; -- fetches third row of employees CLOSE emp_cv1; -- closes both variables FETCH emp_cv2 INTO emp_rec; -- causes error when get_emp_data is invoked END; BEGIN get_emp_data(c1, c2); END; /
Result:
DECLARE * ERROR at line 1: ORA-01001: cursor number is invalid or does not exist ORA-06512: at line 19 ORA-06512: at line 22
Default Values for IN Subprogram Parameters
When you declare a formal IN
parameter, you can specify a default value for it. A formal parameter with a default value is called an optional parameter, because its corresponding actual parameter is optional in a subprogram invocation. If the actual parameter is omitted, then the invocation assigns the default value to the formal parameter. A formal parameter with no default value is called a required parameter, because its corresponding actual parameter is required in a subprogram invocation.
Omitting an actual parameter does not make the value of the corresponding formal parameter NULL
. To make the value of a formal parameter NULL
, specify NULL
as either the default value or the actual parameter.
In Example 9-20, the procedure has one required parameter and two optional parameters.
In Example 9-20, the procedure invocations specify the actual parameters in the same order as their corresponding formal parameters are declared—that is, the invocations use positional notation. Positional notation does not let you omit the second parameter of raise_salary
but specify the third; to do that, you must use either named or mixed notation. For more information, see "Positional, Named, and Mixed Notation for Actual Parameters".
The default value of a formal parameter can be any expression whose value can be assigned to the parameter; that is, the value and parameter must have compatible data types. If a subprogram invocation specifies an actual parameter for the formal parameter, then that invocation does not evaluate the default value.
In Example 9-21, the procedure p
has a parameter whose default value is an invocation of the function f
. The function f
increments the value of a global variable. When p
is invoked without an actual parameter, p
invokes f
, and f
increments the global variable. When p
is invoked with an actual parameter, p
does not invoke f
, and value of the global variable does not change.
Example 9-22 creates a procedure with two required parameters, invokes it, and then adds a third, optional parameter. Because the third parameter is optional, the original invocation remains valid.
Example 9-20 Procedure with Default Parameter Values
DECLARE PROCEDURE raise_salary ( emp_id IN employees.employee_id%TYPE, amount IN employees.salary%TYPE := 100, extra IN employees.salary%TYPE := 50 ) IS BEGIN UPDATE employees SET salary = salary + amount + extra WHERE employee_id = emp_id; END raise_salary; BEGIN raise_salary(120); -- same as raise_salary(120, 100, 50) raise_salary(121, 200); -- same as raise_salary(121, 200, 50) END; /
Example 9-21 Function Provides Default Parameter Value
DECLARE global PLS_INTEGER := 0; FUNCTION f RETURN PLS_INTEGER IS BEGIN DBMS_OUTPUT.PUT_LINE('Inside f.'); global := global + 1; RETURN global * 2; END f; PROCEDURE p ( x IN PLS_INTEGER := f() ) IS BEGIN DBMS_OUTPUT.PUT_LINE ( 'Inside p. ' || ' global = ' || global || ', x = ' || x || '.' ); DBMS_OUTPUT.PUT_LINE('--------------------------------'); END p; PROCEDURE pre_p IS BEGIN DBMS_OUTPUT.PUT_LINE ( 'Before invoking p, global = ' || global || '.' ); DBMS_OUTPUT.PUT_LINE('Invoking p.'); END pre_p; BEGIN pre_p; p(); -- default expression is evaluated pre_p; p(100); -- default expression is not evaluated pre_p; p(); -- default expression is evaluated END; /
Result:
Before invoking p, global = 0. Invoking p. Inside f. Inside p. global = 1, x = 2. -------------------------------- Before invoking p, global = 1. Invoking p. Inside p. global = 1, x = 100. -------------------------------- Before invoking p, global = 1. Invoking p. Inside f. Inside p. global = 2, x = 4. --------------------------------
Example 9-22 Adding Subprogram Parameter Without Changing Existing Invocations
Create procedure:
CREATE OR REPLACE PROCEDURE print_name ( first VARCHAR2, last VARCHAR2 ) AUTHID DEFINER IS BEGIN DBMS_OUTPUT.PUT_LINE(first || ' ' || last); END print_name; /
Invoke procedure:
BEGIN print_name('John', 'Doe'); END; /
Result:
John Doe
Add third parameter with default value:
CREATE OR REPLACE PROCEDURE print_name (
first VARCHAR2,
last VARCHAR2,
mi VARCHAR2 := NULL
) AUTHID DEFINER IS
BEGIN
IF mi IS NULL THEN
DBMS_OUTPUT.PUT_LINE(first || ' ' || last);
ELSE
DBMS_OUTPUT.PUT_LINE(first || ' ' || mi || '. ' || last);
END IF;
END print_name;
/
Invoke procedure:
BEGIN print_name('John', 'Doe'); -- original invocation print_name('John', 'Public', 'Q'); -- new invocation END; /
Result:
John Doe John Q. Public
Positional, Named, and Mixed Notation for Actual Parameters
When invoking a subprogram, you can specify the actual parameters using either positional, named, or mixed notation. Table 9-3 summarizes and compares these notations.
Table 9-3 PL/SQL Actual Parameter Notations
Notation | Syntax | Optional parameters | Advantages | Disadvantages |
---|---|---|---|---|
Positional |
Specify the actual parameters in the same order as the formal parameters are declared. |
You can omit trailing optional parameters. |
Specifying actual parameters in the wrong order can cause problems that are hard to detect, especially if the actual parameters are literals. Subprogram invocations must change if the formal parameter list changes, unless the list only acquires new trailing optional parameters (as in Example 9-22). Reduced code clarity and maintainability. Not recommended if the subprogram has a large number of parameters. |
|
Named |
Specify the actual parameters in any order, using this syntax: formal => actual
|
You can omit any optional parameters. |
There is no wrong order for specifying actual parameters. Subprogram invocations must change only if the formal parameter list acquires new required parameters. Recommended when you invoke a subprogram defined or maintained by someone else. |
|
Mixed |
Start with positional notation, then use named notation for the remaining parameters. |
In the positional notation, you can omit trailing optional parameters; in the named notation, you can omit any optional parameters. |
Convenient when you invoke a subprogram that has required parameters followed by optional parameters, and you must specify only a few of the optional parameters. |
In the positional notation, the wrong order can cause problems that are hard to detect, especially if the actual parameters are literals. Changes to the formal parameter list might require changes in the positional notation. |
In Example 9-23, the procedure invocations use different notations, but are equivalent.
In Example 9-24, the SQL SELECT
statements invoke the PL/SQL function compute_bonus
, using equivalent invocations with different notations.
Example 9-23 Equivalent Invocations with Different Notations in Anonymous Block
DECLARE emp_num NUMBER(6) := 120; bonus NUMBER(6) := 50; PROCEDURE raise_salary ( emp_id NUMBER, amount NUMBER ) IS BEGIN UPDATE employees SET salary = salary + amount WHERE employee_id = emp_id; END raise_salary; BEGIN -- Equivalent invocations: raise_salary(emp_num, bonus); -- positional notation raise_salary(amount => bonus, emp_id => emp_num); -- named notation raise_salary(emp_id => emp_num, amount => bonus); -- named notation raise_salary(emp_num, amount => bonus); -- mixed notation END; /
Example 9-24 Equivalent Invocations with Different Notations in SELECT Statements
CREATE OR REPLACE FUNCTION compute_bonus ( emp_id NUMBER, bonus NUMBER ) RETURN NUMBER AUTHID DEFINER IS emp_sal NUMBER; BEGIN SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id; RETURN emp_sal + bonus; END compute_bonus; / SELECT compute_bonus(120, 50) FROM DUAL; -- positional SELECT compute_bonus(bonus => 50, emp_id => 120) FROM DUAL; -- named SELECT compute_bonus(120, bonus => 50) FROM DUAL; -- mixed