Как создать объект включаюший объект этого же типа, есть ли поддержка рекурсивных объектов?

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

В Object-Relational Developer's Guide нашел ссылки на подчиненные/встроенные типы данных, которые отличаются друг от друга - например, department включает в себя address. В этом документе также есть раздел разрешения круговых ссылок, но опять же, между объектами разных типов. А надо создать объект включающий объект этого же типа:

create or replace type a_obj is object (myself varchar2(10), parent number, children number);
/

Type A_OBJ compiled

create or replace type c_obj is table of ref a_obj;
/

Type C_OBJ compiled

create or replace type a_obj force is object (
    myself varchar2(10), parent a_obj, children c_obj);
/

Warning: Type created with compilation errors.

LINE/COL  ERROR
--------- -------------------------------------------------------------
0/0       PL/SQL: Compilation unit analysis terminated
1/1       PLS-00318: type "A_OBJ" is malformed because 
          it is a non-REF mutually recursive type

Есть ли поддержка рекурсивного объявления объектов? Другими словами, как создать объект включаюший объект этого же типа?


Свободный перевод вопроса Does Oracle Database PL/SQL support recursive objects? от участника @tthomson001


Ответы (2 шт):

Автор решения: 0xdb

Сначало сделайте форвард декларацию типа данных (без аттрибутов), затем атрибуту parent задайте тип REF:

create or replace type a_obj
/

Type A_OBJ compiled

create or replace type c_obj is table of ref a_obj
/

Type C_OBJ compiled

create or replace type a_obj is object (
    myself   varchar2(10), parent ref a_obj, children c_obj)
/

Type A_OBJ compiled

Свободный перевод ответа от участника @MT0

→ Ссылка
Автор решения: 0xdb

Если нужно решение на чистом PL/SQL, то есть, нет таблицы с этим типом данных и ссылка через REF невозможна, то форвард декларация не будет работать:

create or replace type a_obj
/
Type created.

create or replace type c_obj is table of a_obj
/
Warning: Type created with compilation errors.
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      PL/SQL: Compilation unit analysis terminated
1/24     PLS-00311: the declaration of "A_OBJ" is incomplete or malformed

Необходимо создать базвоый объект, и с ним создать атрибут со вложенной таблицей:

create or replace type baseobj force is object (myself varchar2 (10)) not instantiable not final
/
create or replace type nodetab is table of baseobj
/
create or replace type nodeobj under baseobj (children nodetab)
/

Пример использованя для иерархического дерева:

declare 
    root nodeobj;
    procedure printout (n nodeobj, l int := 0) is
    begin
        dbms_output.put_line (lpad (' ', l*4)||n.myself||'->'||n.children.count||' nodes');
        for i in 1..n.children.count loop
            printout (treat (n.children(i) as nodeobj), l+1);
        end loop;
    end;
begin 
    root := nodeobj (
        'root', nodetab (
            nodeobj ('node1', 
                nodetab (nodeobj ('leaf11', nodetab ()), nodeobj ('leaf12', nodetab ()))),
            nodeobj ('node2', 
                nodetab (nodeobj ('leaf21', nodetab ()), nodeobj ('leaf22', nodetab ())))));
    printout (root);
end;
/

Результат:

root->2 nodes
    node1->2 nodes
        leaf11->0 nodes
        leaf12->0 nodes
    node2->2 nodes
        leaf21->0 nodes
        leaf22->0 nodes
→ Ссылка