オーバーロードされたサブプログラム
PL/SQLでは、ネストしたサブプログラム、パッケージ・サブプログラムおよび型のメソッドをオーバーロードできます。仮パラメータの名前、数、順序またはデータ型のファミリが異なっている場合、同じ名前を複数のサブプログラムで使用できます。(データ型ファミリは、データ型とそのサブタイプです。事前定義のPL/SQLデータ型のデータ型ファミリは、「PL/SQLの事前定義のデータ型」を参照してください。ユーザー定義のPL/SQLサブタイプの詳細は、「ユーザー定義のPL/SQLサブタイプ」を参照してください。)仮パラメータの違いが名前のみである場合、名前表記法を使用して対応する実パラメータを指定する必要があります。(名前表記法の詳細は、実パラメータの位置表記法、名前表記法および混合表記法を参照してください。)
例9-26では、同じ名前(initialize
)を持つ2つのサブプログラムを定義しています。プロシージャでは様々な型のコレクションを初期化します。これらのプロシージャは同じ処理を実行しているため、同じ名前を与えるのが論理的です。
この2つのinitialize
プロシージャは、同じブロック、サブプログラム、パッケージまたは型本体の中に置くことができます。PL/SQLは仮パラメータをチェックして、どちらのプロシージャを起動するかを判断します。PL/SQLが使用するinitialize
のバージョンは、プロシージャをdate_tab_typ
パラメータまたはnum_tab_typ
パラメータのどちらで起動するかによって異なります。
パッケージ内のオーバーロードされたプロシージャの例は、例11-9を参照してください。
ここでのトピック
例9-26 オーバーロードされたサブプログラム
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; /
結果:
Invoked first version Invoked second version
数値データ型のみが異なる仮パラメータ
サブプログラムの仮パラメータの違いが数値データ型のみの場合、それらのサブプログラムはオーバーロードできます。ファンクションの複数のバージョンが同じ名前を使用でき、それぞれが異なる数値型を受け取ることができるため、この手法は数値演算Application Programming Interface(API)を記述する場合に有効です。たとえば、BINARY_FLOAT
を受け取るファンクションはより高速で、BINARY_DOUBLE
を受け取るファンクションは精度がより高くなる場合があります。
オーバーロードされたサブプログラムにパラメータを渡す場合、次のことに注意して、問題または予期しない結果を回避します。
-
予期されるパラメータ・セットごとに、目的のバージョンのサブプログラムが起動されることを確認します。
たとえば、オーバーロードされるファンクションが
BINARY_FLOAT
およびBINARY_DOUBLE
を受け取る場合、「5.0」
のようなVARCHAR2
リテラルを渡すと、どちらのファンクションが起動されるかを確認します。 -
数値リテラルを修飾したり、変換ファンクションを使用して、目的のパラメータ型を明示します。
たとえば、
5.0f
(BINARY_FLOAT
)、5.0d
(BINARY_DOUBLE
)のようなリテラル、またはTO_BINARY_FLOAT
、TO_BINARY_DOUBLE
、TO_NUMBER
のような変換ファンクションを使用します。
PL/SQLは、次の順序で、一致する数値パラメータを検索します。
-
PLS_INTEGER
(または同じデータ型であるBINARY_INTEGER
) -
NUMBER
-
BINARY_FLOAT
-
BINARY_DOUBLE
VARCHAR2
値は、NUMBER
、BINARY_FLOAT
またはBINARY_DOUBLE
パラメータに一致します。
PL/SQLは、指定されたパラメータに最初に一致してオーバーロードされるサブプログラムを使用します。たとえば、SQRT
ファンクションは1つのパラメータを受け取ります。NUMBER
、BINARY_FLOAT
またはBINARY_DOUBLE
パラメータを受け取るオーバーロードされるファンクションがあるとします。PLS_INTEGER
パラメータを渡した場合、最初に一致してオーバーロードされるファンクションは、NUMBER
パラメータを持つファンクションです。
NUMBER
パラメータを受け取るSQRT
ファンクションは、最も低速となる可能性が高くなります。より高速なバージョンを使用するには、パラメータをSQRT
ファンクションに渡す前に、TO_BINARY_FLOAT
またはTO_BINARY_DOUBLE
ファンクションを使用して、そのパラメータを別のデータ型に変換します。
PL/SQLは、パラメータを別のデータ型に変換する必要がある場合、まずそのパラメータをより上位のデータ型に変換しようとします。たとえば:
-
ATAN2
ファンクションは、同じ型の2つのパラメータを受け取ります。異なる型のパラメータを渡した場合(たとえば、1つがPLS_INTEGER
で、1つがBINARY_FLOAT
の場合)、PL/SQLは、両方のパラメータでより高度な型が使用されている場合に一致するものを検索します。この例では、2つのBINARY_FLOAT
パラメータを受け取るバージョンのATAN2
が使用され、PLS_INTEGER
パラメータは、上位変換されます。 -
あるファンクションは、異なる型の2つのパラメータを受け取ります。オーバーロードされるバージョンの1つは、
PLS_INTEGER
パラメータおよびBINARY_FLOAT
パラメータを受け取ります。別のオーバーロードされるバージョンは、NUMBER
パラメータおよびBINARY_DOUBLE
パラメータを受け取ります。このファンクションを起動して、2つのNUMBER
パラメータを渡した場合、PL/SQLは、まず2つ目のパラメータがBINARY_FLOAT
のオーバーロードされるバージョンを検出します。このパラメータは、他方のオーバーロードされるバージョンのBINARY_DOUBLE
パラメータよりも一致度が高いため、次にPL/SQLは下位検索し、1つ目のNUMBER
パラメータをPLS_INTEGER
に変換します。
オーバーロードできないサブプログラム
次のサブプログラムはオーバーロードできません。
-
スタンドアロン・サブプログラム
-
仮パラメータの違いがモードのみのサブプログラム。たとえば:
PROCEDURE s (p IN VARCHAR2) IS ... PROCEDURE s (p OUT VARCHAR2) IS ...
-
仮パラメータの違いがサブタイプのみのサブプログラム。たとえば:
PROCEDURE s (p INTEGER) IS ... PROCEDURE s (p REAL) IS ...
INTEGER
およびREAL
は、NUMBER
のサブタイプであるため、同じデータ型のファミリに属しています。 -
戻り値のデータ型のみが異なるファンクション(そのデータ型のファミリが異なっている場合でも)。たとえば:
FUNCTION f (p INTEGER) RETURN BOOLEAN IS ... FUNCTION f (p INTEGER) RETURN INTEGER IS ...
サブプログラムのオーバーロード・エラー
PL/SQLコンパイラは、起動されたサブプログラムを判別できないと判断するとすぐに、オーバーロード・エラーを捕捉します。複数のサブプログラムに同一のヘッダーがある場合、サブプログラム自体のコンパイル(サブプログラムがネストされている場合)、またはサブプログラムを宣言しているパッケージ仕様部のコンパイルを試行すると、コンパイラはオーバーロード・エラーを捕捉します。それ以外の場合、サブプログラムの曖昧な起動のコンパイルを試行すると、コンパイラはエラーを捕捉します。
例9-27に示す、同一のヘッダーを持つ複数のサブプログラムを宣言しているパッケージ仕様部をコンパイルしようとすると、コンパイル時エラーPLS-00305が発生します。
例9-28に示すパッケージ仕様部は、仮パラメータの違いがサブタイプのみのサブプログラムはオーバーロードできないという規則に違反していますが、エラーを生成せずにコンパイルできます。
ただし、例9-29に示すようにpkg2
.s
の起動をコンパイルしようとすると、コンパイル時エラーPLS-00307が発生します。
例9-30のように、オーバーロードされたサブプログラムの仮パラメータに別の名前を付けることによって、例9-28に示されているオーバーロード・エラーを修正するとします。
これによって、名前表記法を使用して実パラメータを指定する場合に、エラーを生成せずにpkg2
.s
の起動をコンパイルできます(例9-31を参照)。(例9-29に示されているように、位置表記法を使用して実パラメータを指定すると、コンパイル時エラーPLS-00307が発生します。)
例9-32に示すパッケージ仕様部は、オーバーロード規則に違反していないため、エラーを生成せずにコンパイルできます。ただし、オーバーロードされたプロシージャを起動すると、例9-33の2つ目の起動に示すように、コンパイル時エラーPLS-00307が発生します。
どのサブプログラムが起動されたかを特定しようとしたとき、PL/SQLコンパイラは、暗黙的にあるパラメータを一致するタイプに変換すると、暗黙的に一致するタイプに変換できる別のパラメータを検索します。複数の一致がある場合、例9-34に示すように、コンパイル時エラーPLS-00307が発生します。
初期化パラメータPLSQL_IMPLICIT_CONVERSION_BOOL
は、BOOLEAN
およびその他のタイプ・パラメータを含むオーバーロードされたサブプログラムの処理方法に影響します。サブプログラムがBOOLEAN
型と数値型または文字型でオーバーロードされている場合、PLSQL_IMPLICIT_CONVERSION_BOOL
をTRUE
に設定すると、コンパイル時エラーが発生する可能性があります。ただし、パラメータがFALSE
に設定されている場合、サブプログラムは引数を暗黙的に代替型に変換します。
たとえば、PLSQL_IMPLICIT_CONVERSION_BOOL
がFALSE
に設定されている場合、文字列値'1'
、または文字列で表される0以外の数値は、例9-35のように、デフォルトで数値に変換されます。PLSQL_IMPLICIT_CONVERSION_BOOL
がTRUE
に設定されている場合、'1'
はBOOLEAN
または数値に変換でき、例9-36のようにPLS-00307エラーが発生します。このエラーは、指定された引数をBOOLEAN
または代替オーバーロード・タイプのいずれかに変換できるときに発生します。
関連項目:
-
PLSQL_IMPLICIT_CONVERSION_BOOL
パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください
例9-27 コンパイル時エラーの原因となるオーバーロード・エラー
CREATE OR REPLACE PACKAGE pkg1 AUTHID DEFINER IS
PROCEDURE s (p VARCHAR2);
PROCEDURE s (p VARCHAR2);
END pkg1;
/
例9-28 正常にコンパイルが行われるオーバーロード・エラー
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;
/
例9-29 コンパイル時エラーの原因となる例9-28のサブプログラムの起動
CREATE OR REPLACE PROCEDURE p AUTHID DEFINER IS
a pkg2.t1 := 'a';
BEGIN
pkg2.s(a); -- Causes compile-time error PLS-00307
END p;
/
例9-30 例9-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;
/
例9-31 例9-30のサブプログラムの起動
CREATE OR REPLACE PROCEDURE p AUTHID DEFINER IS
a pkg2.t1 := 'a';
BEGIN
pkg2.s(p1=>a); -- Compiles without error
END p;
/
例9-32 オーバーロード・エラーが含まれていないパッケージ仕様部
CREATE OR REPLACE PACKAGE pkg3 AUTHID DEFINER IS
PROCEDURE s (p1 VARCHAR2);
PROCEDURE s (p1 VARCHAR2, p2 VARCHAR2 := 'p2');
END pkg3;
/
例9-33 適切にオーバーロードされたサブプログラムの不適切な起動
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;
/
例9-34 パラメータの暗黙的な変換によるオーバーロード・エラー
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;
/
例9-35 数値への暗黙的な変換の成功
この例の正常な実行は、FALSE
に設定されている初期化パラメータPLSQL_IMPLICIT_CONVERSION_BOOL
によって異なります。パラメータはデフォルトでFALSE
に設定されています。
ALTER SESSION SET PLSQL_IMPLICIT_CONVERSION_BOOL = FALSE;
CREATE OR REPLACE PACKAGE pkg1 AUTHID DEFINER IS
PROCEDURE s (p INTEGER);
PROCEDURE s (p BOOLEAN);
END pkg1;
/
CREATE OR REPLACE PACKAGE BODY pkg1 IS
PROCEDURE s (p INTEGER) AS
BEGIN
dbms_output.put_line ( 'Integer' );
END;
PROCEDURE s (p BOOLEAN) AS
BEGIN
dbms_output.put_line ( 'Boolean' );
END;
END pkg1;
/
BEGIN
pkg1.s('1'); -- Compiles without error
END;
/
結果:
Integer
例9-36 BOOLEANまたは数値の暗黙的な変換によるオーバーロード・エラー
この例では、例9-35で宣言されたサブプログラムを使用します。
ALTER SESSION SET PLSQL_IMPLICIT_CONVERSION_BOOL = TRUE;
exec pkg1.s('1'); -- Causes compile-time error PLS-00307
プロシージャs
がINTEGER
ではなくVARCHAR2を受け入れ、番号1
がプロシージャに指定されている場合、同じエラーが発生します。