Перегрузка подпрограмм: программирование на PL/SQL

Перегрузка подпрограмм в PL/SQLПрограммы, которые существуют в одной области видимости и имеют одинаковые имена, называются перегруженными. PL/SQL поддерживает перегрузку процедур и функций в разделе объявлений блока (именованного или неименованного), в теле и специфи­кации пакета, а также в объявлении объектного типа. Перегрузка — это очень мощный механизм, и вы должны научиться использовать все его возможности.


Оглавление статьи[Показать]


В следующем простом примере представлены три перегруженные подпрограммы, определенные в разделе объявлений анонимного блока (а следовательно, являющихся локальными):

DECLARE
   /* Первая версия получает параметр DATE. */
   FUNCTION value_ok (date_in IN DATE) RETURN BOOLEAN IS 
   BEGIN
      RETURN date_in <= SYSDATE;
   END;

   /* Вторая версия получает параметр NUMBER. */
   FUNCTION value_ok (number_in IN NUMBER) RETURN BOOLEAN IS 
   BEGIN
      RETURN number_in > 0;
   END;

   /* Третья версия - процедура! */
   PROCEDURE value_ok (number_in IN NUMBER) IS 
   BEGIN
      IF number_in > 0 THEN
         DBMS_OUTPUT.PUT_LINE (number_in || 'is OK!');
      ELSE
         DBMS_OUTPUT.PUT_LINE (number_in || 'is not OK!');
      END IF;
   END;
BEGIN

Когда исполняемое ядро PL/SQL встречает в программе строку вида

IF value_ok (SYSDATE) THEN ...

список фактических параметров сравнивается со списками формальных параметров разных перегруженных модулей. В результате PL/SQL выполняет код того модуля, для которого указанные списки совпадают.

Перегрузку также называют статическим полиморфизмом. Термином «полимор­физм» обозначается возможность языка определять и использовать несколько программ с одинаковыми именами. Если вызываемый вариант определяется на стадии компиляции — это статический полиморфизм. Если решение принимается во время выполнения, то используется термин «динамический полиморфизм»; этот вид полиморфизма обеспечивается наследованием объектных типов.

Перегрузка способна сильно упростить жизнь как вам, так и другим разработчикам. Она консолидирует интерфейсы вызова многих похожих программ в одно имя модуля. «Информационное бремя» перекладывается с разработчика на программный продукт. Например, вам не придется пытаться запомнить шесть разных имен для программ, до­бавляющих значения (даты, строки, флаги, числа и т. д.) в разные коллекции. Вместо этого вы просто сообщаете компилятору, что вы хотите добавить значение, и передаете это значение. PL/SQL и перегруженные программы определяют, что вы хотите сделать, и выполняют необходимые действия за вас.

При создании перегруженных подпрограмм вы потратите больше времени на проекти­рование и реализацию, чем с отдельными, автономными программами. Дополнительное время с лихвой окупится в будущем, потому что и вам, и другим разработчикам будет проще работать с вашим кодом.

 

Преимущества перегрузки

Перегрузка модулей наиболее уместна в следующих ситуациях:

 

BEGIN
   DBMS_SQL.EXECUTE ('CREATE TABLE xyz ...');

Без применения перегрузки вы должны вызвать функцию

DECLARE
   feedback PLS_INTEGER;
BEGIN
   feedback := DBMS_SQL.EXECUTE ('CREATE TABLE xyz ...');

а затем игнорировать переменную feedback.

DBMS_SQL.DEFINE_COLUMN (cur, 1, DBMS_UTILITY.GET_TIME);

Конкретное значение роли не играет; мы должны указать «это число», а не привести какое-то конкретное число. Перегрузка обеспечивает элегантное решение этой проблемы. Сейчас мы рассмотрим типичный пример перегрузки, а затем разберемся с ограниче­ниями и рекомендациями по поводу перегрузки.

 

Поддержка разных комбинаций данных

Перегрузка может использоваться для выполнения одного действия с разными комбина­циями данных. Как упоминалось ранее, такая разновидность перегрузки предоставляет не столько общее имя для разных операций, как разные способы вызова одной операции. Возьмем DBMS_OUTPUT.PUT_LINE: эта встроенная функция может использоваться для выво­да значений любых типов данных, которые могут быть явно или неявно преобразованы в строку. Интересно, что в предшествующих версиях Oracle Database (7, 8, 8i, 9i) эта про­цедура была перегружена, но в Oracle Database 10g и выше она не перегружается! Таким образом, если вам потребуется вывести выражение, которое не может быть неявно преоб­разовано в строку, вы не сможете вызвать DBMS_OUTPUT. PUT_LINE и передать это выражение. И что из того, спросите вы? PL/SQL неявно преобразует числа и даты в строки. Какие еще данные приходится выводить? Для начала — как насчет логических значений? Чтобы вывести значение логического выражения, придется написать команду IF сле­дующего вида:

IF l_student_is_registered 
THEN
   DBMS_OUTPUT.PUT_LINE ('TRUE');
ELSE
   DBMS_OUTPUT.PUT_LINE ('FALSE');
END IF;

Глупо, вам не кажется? И разве это не напрасная потеря времени? К счастью, проблема решается очень просто. Постройте на базе DBMS_OUTPUT. PUT_LINE свой пакет с множеством перегрузок. Ниже приводится сильно сокращенная версия такого пакета. При желании вы сможете легко расширить ее, как я делаю в процедуре do.pl. Часть спецификации пакета выглядит так:

PACKAGE do 
IS
   PROCEDURE pl (boolean_in IN BOOLEAN);
   /* Вывод строки. */
   PROCEDURE pl (char_in IN VARCHAR2);
   /* Вывод строки и значения BOOLEAN. */
   PROCEDURE pl (
      char_in	IN	VARCHAR2,
      boolean_in IN	BOOLEAN
   );
   PROCEDURE pl (xml_in IN SYS.XMLType);
END do;

Пакет просто расширяет DBMS_OUTPUT.PUT_LINE. При использовании do.pl я могу вывести логическое значение без написания команды IF, как в следующем примере:

DECLARE
   v_is_valid BOOLEAN :=
      book_info.is_valid_isbn ('5-88888-66');
BEGIN
   do.pl (v_is_valid);

Более того, do.pl можно применять даже к сложным типам данных — таким, как XMLType:

DECLARE
   doc xmltype;
BEGIN
   SELECT ea.report 
   INTO doc
   FROM env_analysis ea 
   WHERE company= 'ACME SILVERPLATING'; 
   do.pl (doc);
END;

Ограничения на использование перегрузки

При выполнении перегрузки необходимо учитывать несколько обстоятельств. Ис­полнительное ядро PL/SQL как на этапе компиляции, так и на этапе запуска должно быть в состоянии отличить друг от друга перегруженные версии подпрограммы; ведь оно не может выполнять две подпрограммы одновременно. Так как все перегруженные версии имеют одинаковые имена, исполнительное ядро не может различать их по име­нам. Для определения того, какую из версий следует выполнить, PL/SQL использует списки параметров и/или сведения о типе программы (процедура или функция). Все это приводит к тому, что на перегруженные программы накладывается ряд ограничений. У перегруженных программ типы хотя бы одного параметра должны принадлежать к разным семействам. Типы данных INTEGER, REAL, DECIMAL, FLOAT и т. д. являются число­выми подтипами, а типы CHAR, VARCHAR2 и LONG — символьными. Если соответствующие параметры отличаются только подтипом, то есть принадлежат к одному супертипу, у PL/SQL не будет достаточной информации для выбора выполняемой программы.

В следующем разделе описаны некоторые усовершенствования Oracle10g (и по­следующих версий), относящиеся к перегрузке числовых типов.

 

Перегрузка числовых типов

В OraclelOg появилась возможность перегрузки двух подпрограмм, различающихся только числовым типом формальных параметров. Рассмотрим конкретный пример:

DECLARE
   PROCEDURE procl (n IN PLS_INTEGER) IS 
   BEGIN
      DBMS_OUTPUT.PUT_LINE ('pls_integer version');
   END;

   PROCEDURE proc1 (n IN NUMBER) IS 
   BEGIN
      DBMS_OUTPUT.PUT_LINE ('number version');
   END;

BEGIN
   proc1 (1.1); 
   proc1 (1);
END;

При попытке выполнить этот код в Oracle9i происходит ошибка:

ORA-06550: line 14, column 4:
PLS-00307: too many declarations of 'PROC1' match this call

Однако при выполнении того же блока в Oracle10g и Oracle11g результат будет таким:

number version 
pls_integer version

Теперь компилятор PL/SQL различает два вызова. Обратите внимание: при передаче не-целочисленного значения вызывается «NUMBER-версия» программы. Это объясняется тем, что PL/SQL при определении соответствия перебирает типы в следующем по­рядке: сначала PLS_INTEGER или BINARY_INTEGER, затем NUMBER, BINARY_FLOAT и наконец, BINARY_DOUBLE. Используется первая перегруженная программа, которая соответствует переданным значениям фактических аргументов.

Хотя эта новая гибкая возможность чрезвычайно удобна, будьте осторожны при ис­пользовании этой крайне неочевидной перегрузки — убедитесь в том, что она работает именно так, как предполагалось. Протестируйте свой код с разными входными данными и проверьте результаты. Помните, что в качестве числового параметра может быть пере­дана строка вида «156.4»; протестируйте и такие данные.

Также можно уточнить тип числовых значений и использовать функции преобразо­вания для явного выбора перегруженной версии. Скажем, если значение 5.0 должно передаваться в формате BINARY_FLOAT, используйте обозначение 5.0f или функцию пре­образования TO_BINARY_FLOAT(5.0).

Вас заинтересует / Intresting for you:

Управление приложениями PL/SQL...
Управление приложениями PL/SQL... 4651 просмотров Stas Belkov Thu, 16 Jul 2020, 06:20:48
Встроенные методы коллекций PL...
Встроенные методы коллекций PL... 14847 просмотров sepia Tue, 29 Oct 2019, 09:54:01
Основы языка PL/SQL: использов...
Основы языка PL/SQL: использов... 4701 просмотров Ирина Светлова Tue, 06 Feb 2018, 14:04:03
Работа с числами в PL/SQL на п...
Работа с числами в PL/SQL на п... 45258 просмотров Antoniy Mon, 28 May 2018, 16:45:11
Печать
Войдите чтобы комментировать