8.9 Overloaded Subprograms
PL/SQL lets you overload nested subprograms, package subprograms, and type methods. You can use the same name for several different subprograms if their formal parameters differ in name, number, order, or data type family. (A data type family is a data type and its subtypes. For the data type families of predefined PL/SQL data types, see PL/SQL Predefined Data Types. For information about user-defined PL/SQL subtypes, see "User-Defined PL/SQL Subtypes".) If formal parameters differ only in name, then you must use named notation to specify the corresponding actual parameters. (For information about named notation, see "Positional, Named, and Mixed Notation for Actual Parameters".)
Example 8-26 defines two subprograms with the same name, initialize. The procedures initialize different types of collections. Because the processing in the procedures is the same, it is logical to give them the same name.
You can put the two initialize procedures in the same block, subprogram, package, or type body. PL/SQL determines which procedure to invoke by checking their formal parameters. The version of initialize that PL/SQL uses depends on whether you invoke the procedure with a date_tab_typ or num_tab_typ parameter.
For an example of an overloaded procedure in a package, see Example 10-9.
Topics
Example 8-26 Overloaded Subprogram
DECLARE TYPE date_tab_typ IS TABLE OF DATE INDEX BY PLS_INTEGER; TYPE num_tab_typ IS TABLE OF NUMBER INDEX BY PLS_INTEGER; hiredate_tab date_tab_typ; sal_tab num_tab_typ; PROCEDURE initialize (tab OUT date_tab_typ, n INTEGER) IS BEGIN DBMS_OUTPUT.PUT_LINE('Invoked first version'); FOR i IN 1..n LOOP tab(i) := SYSDATE; END LOOP; END initialize; PROCEDURE initialize (tab OUT num_tab_typ, n INTEGER) IS BEGIN DBMS_OUTPUT.PUT_LINE('Invoked second version'); FOR i IN 1..n LOOP tab(i) := 0.0; END LOOP; END initialize; BEGIN initialize(hiredate_tab, 50); initialize(sal_tab, 100); END; /
Result:
Invoked first version Invoked second version
8.9.1 Formal Parameters that Differ Only in Numeric Data Type
You can overload subprograms if their formal parameters differ only in numeric data type. This technique is useful in writing mathematical application programming interfaces (APIs), because several versions of a function can use the same name, and each can accept a different numeric type. For example, a function that accepts BINARY_FLOAT might be faster, while a function that accepts BINARY_DOUBLE might be more precise.
To avoid problems or unexpected results when passing parameters to such overloaded subprograms:
-
Ensure that the expected version of a subprogram is invoked for each set of expected parameters.
For example, if you have overloaded functions that accept
BINARY_FLOATandBINARY_DOUBLE, which is invoked if you pass aVARCHAR2literal like'5.0'? -
Qualify numeric literals and use conversion functions to make clear what the intended parameter types are.
For example, use literals such as
5.0f(forBINARY_FLOAT),5.0d(forBINARY_DOUBLE), or conversion functions such asTO_BINARY_FLOAT,TO_BINARY_DOUBLE, andTO_NUMBER.
PL/SQL looks for matching numeric parameters in this order:
-
PLS_INTEGER(orBINARY_INTEGER, an identical data type) -
NUMBER -
BINARY_FLOAT -
BINARY_DOUBLE
A VARCHAR2 value can match a NUMBER, BINARY_FLOAT, or BINARY_DOUBLE parameter.
PL/SQL uses the first overloaded subprogram that matches the supplied parameters. For example, the SQRT function takes a single parameter. There are overloaded versions that accept a NUMBER, a BINARY_FLOAT, or a BINARY_DOUBLE parameter. If you pass a PLS_INTEGER parameter, the first matching overload is the one with a NUMBER parameter.
The SQRT function that takes a NUMBER parameter is likely to be slowest. To use a faster version, use the TO_BINARY_FLOAT or TO_BINARY_DOUBLE function to convert the parameter to another data type before passing it to the SQRT function.
If PL/SQL must convert a parameter to another data type, it first tries to convert it to a higher data type. For example:
-
The
ATAN2function takes two parameters of the same type. If you pass parameters of different types—for example, onePLS_INTEGERand oneBINARY_FLOAT—PL/SQL tries to find a match where both parameters use the higher type. In this case, that is the version ofATAN2that takes twoBINARY_FLOATparameters; thePLS_INTEGERparameter is converted upwards. -
A function takes two parameters of different types. One overloaded version takes a
PLS_INTEGERand aBINARY_FLOATparameter. Another overloaded version takes aNUMBERand aBINARY_DOUBLEparameter. If you invoke this function and pass twoNUMBERparameters, PL/SQL first finds the overloaded version where the second parameter isBINARY_FLOAT. Because this parameter is a closer match than theBINARY_DOUBLEparameter in the other overload, PL/SQL then looks downward and converts the firstNUMBERparameter toPLS_INTEGER.
8.9.2 Subprograms that You Cannot Overload
You cannot overload these subprograms:
-
Standalone subprograms
-
Subprograms whose formal parameters differ only in mode; for example:
PROCEDURE s (p IN VARCHAR2) IS ... PROCEDURE s (p OUT VARCHAR2) IS ...
-
Subprograms whose formal parameters differ only in subtype; for example:
PROCEDURE s (p INTEGER) IS ... PROCEDURE s (p REAL) IS ...
INTEGERandREALare subtypes ofNUMBER, so they belong to the same data type family. -
Functions that differ only in return value data type, even if the data types are in different families; for example:
FUNCTION f (p INTEGER) RETURN BOOLEAN IS ... FUNCTION f (p INTEGER) RETURN INTEGER IS ...
8.9.3 Subprogram Overload Errors
The PL/SQL compiler catches overload errors as soon as it determines that it cannot tell which subprogram was invoked. When subprograms have identical headings, the compiler catches the overload error when you try to compile the subprograms themselves (if they are nested) or when you try to compile the package specification that declares them. Otherwise, the compiler catches the error when you try to compile an ambiguous invocation of a subprogram.
When you try to compile the package specification in Example 8-27, which declares subprograms with identical headings, you get compile-time error PLS-00305.
Although the package specification in Example 8-28 violates the rule that you cannot overload subprograms whose formal parameters differ only in subtype, you can compile it without error.
However, when you try to compile an invocation of pkg2.s, as in Example 8-29, you get compile-time error PLS-00307.
Suppose that you correct the overload error in Example 8-28 by giving the formal parameters of the overloaded subprograms different names, as in Example 8-30.
Now you can compile an invocation of pkg2.s without error if you specify the actual parameter with named notation, as in Example 8-31. (If you specify the actual parameter with positional notation, as in Example 8-29, you still get compile-time error PLS-00307.)
The package specification in Example 8-32 violates no overload rules and compiles without error. However, you can still get compile-time error PLS-00307 when invoking its overloaded procedure, as in the second invocation in Example 8-33.
When trying to determine which subprogram was invoked, if the PL/SQL compiler implicitly converts one parameter to a matching type, then the compiler looks for other parameters that it can implicitly convert to matching types. If there is more than one match, then compile-time error PLS-00307 occurs, as in Example 8-34.
Example 8-27 Overload Error Causes Compile-Time Error
CREATE OR REPLACE PACKAGE pkg1 AUTHID DEFINER IS PROCEDURE s (p VARCHAR2); PROCEDURE s (p VARCHAR2); END pkg1; /
Example 8-28 Overload Error Compiles Successfully
CREATE OR REPLACE PACKAGE pkg2 AUTHID DEFINER IS SUBTYPE t1 IS VARCHAR2(10); SUBTYPE t2 IS VARCHAR2(10); PROCEDURE s (p t1); PROCEDURE s (p t2); END pkg2; /
Example 8-29 Invoking Subprogram in Example 8-28 Causes Compile-Time Error
CREATE OR REPLACE PROCEDURE p AUTHID DEFINER IS
a pkg2.t1 := 'a';
BEGIN
pkg2.s(a); -- Causes compile-time error PLS-00307
END p;
/
Example 8-30 Correcting Overload Error in Example 8-28
CREATE OR REPLACE PACKAGE pkg2 AUTHID DEFINER IS SUBTYPE t1 IS VARCHAR2(10); SUBTYPE t2 IS VARCHAR2(10); PROCEDURE s (p1 t1); PROCEDURE s (p2 t2); END pkg2; /
Example 8-31 Invoking Subprogram in Example 8-30
CREATE OR REPLACE PROCEDURE p AUTHID DEFINER IS
a pkg2.t1 := 'a';
BEGIN
pkg2.s(p1=>a); -- Compiles without error
END p;
/
Example 8-32 Package Specification Without Overload Errors
CREATE OR REPLACE PACKAGE pkg3 AUTHID DEFINER IS PROCEDURE s (p1 VARCHAR2); PROCEDURE s (p1 VARCHAR2, p2 VARCHAR2 := 'p2'); END pkg3; /
Example 8-33 Improper Invocation of Properly Overloaded Subprogram
CREATE OR REPLACE PROCEDURE p AUTHID DEFINER IS a1 VARCHAR2(10) := 'a1'; a2 VARCHAR2(10) := 'a2'; BEGIN pkg3.s(p1=>a1, p2=>a2); -- Compiles without error pkg3.s(p1=>a1); -- Causes compile-time error PLS-00307 END p; /
Example 8-34 Implicit Conversion of Parameters Causes Overload Error
CREATE OR REPLACE PACKAGE pack1 AUTHID DEFINER AS PROCEDURE proc1 (a NUMBER, b VARCHAR2); PROCEDURE proc1 (a NUMBER, b NUMBER); END; / CREATE OR REPLACE PACKAGE BODY pack1 AS PROCEDURE proc1 (a NUMBER, b VARCHAR2) IS BEGIN NULL; END; PROCEDURE proc1 (a NUMBER, b NUMBER) IS BEGIN NULL; END; END; / BEGIN pack1.proc1(1,'2'); -- Compiles without error pack1.proc1(1,2); -- Compiles without error pack1.proc1('1','2'); -- Causes compile-time error PLS-00307 pack1.proc1('1',2); -- Causes compile-time error PLS-00307 END; /