Возможно ли создать объектные типы данных внутри пакета?
Возможно ли создать объектные типы данных внутри пакета?
Нечто подобное:
create or replace package my_package as
type my_type as object (
id number(15)
);
end;
Завершится ошибкой:
Error(3,9): PLS-00540: object not supported in this context.
В конечном итоге, хотел бы использовать полиморфизм, а также дать объектам доступ к таблицам и использовать PL/SQL, что недопустимо в типах, определенных вне пакетов.
Свободный перевод Possible to create Oracle Database object types inside of PL/SQL? от участника @jlpp
Ответы (2 шт):
Основной упор при дизайне объектно ориентированных расширений БД был направлен на реализацию ORD (Object-oriented Database Model). Поэтому, пользовательские (или объектные) типы данных могут быть созданы только в SQL, но испольоваться они могут без всяких ограничений в PL/SQL контексте.
Например, определим два новых типа данных (UDT=user defined type) унаследованых (inheritance) от одного абстрактного (ADT=abstract data type):
create or replace type tbase force as object (
msg varchar2 (16),
member function print return varchar2) not instantiable not final
/
create or replace type tdate under tbase (
overriding member function print return varchar2) instantiable final
/
create or replace type ttime under tbase (
overriding member function print return varchar2) instantiable final
/
Вся логика этих типов данных реализуется в их теле (type body). Использовать можно всё, что доступно в пакетах или блоках PL/SQL, например, статический и динамический SQL, внутренние PL/SQL типы данных, исключения и т.п.:
create or replace type body tdate as
overriding member function print return varchar2 is
begin
return self.msg||' '||to_char (sysdate, 'dd Mon'); end;
end;
/
create or replace type body ttime as
overriding member function print return varchar2 is
begin
return self.msg||' '||to_char (sysdate, 'hh24:mi'); end;
end;
/
Не только небольшой функционал, но и полностью всё приложение может быть реализовано как пользовательский тип данных:
create or replace type tappl force as object (
name varchar2 (16),
member function main return char) instantiable final
/
create or replace type body tappl is
member function main return char is
function print (what tbase) return varchar2 is
begin return what.print;
end;
begin
dbms_output.put_line (
self.name||': '||print (tdate ('Сегодня'))||', '||print (ttime ('сейчас')));
return 'ok';
end;
end;
/
Выше простейший пример полиморфизма (polymorphism) -- для каждго из экземпляров по ссылке на базовый тип данных будет вызвана своя функция print.
Для запуска этого небольшого прилижения потребуется всего лишь анонимный блок:
var ret char
exec :ret := tappl ('Новости').main
Новости: Сегодня 15 Jul, сейчас 16:45
RET
--
ok
Цитата из главы 3.1 Declaring and Initializing Objects in PL/SQL книги официальной документации Object-Relational Developer's Guide:
Using object types in a PL/SQL block, subprogram, or package is a two-step process.
You must define object types using the SQL statement CREATE TYPE, in SQL*Plus or other similar programs.
After an object type is defined and installed in the schema, you can use it in any PL/SQL block, subprogram, or package.
In PL/SQL, you then declare a variable whose data type is the user-defined type or ADT that you just defined.
Так что, к сожалению, нет, создать объектные типы данных внутри пакета невозможно.
Свободные переводы ответа от участника @l0b0, обьединённого с ответом от участника @user272735