A REF
must refer to a row. You cannot pass SELF
, since it is not a reference.
One way to make this work is to create a hidden table:
create table shadow_person of person;
And every instance secrently creates a row in that table:
CONSTRUCTOR FUNCTION PERSON
RETURN SELF AS RESULT IS
v_ref_person ref person;
BEGIN
insert into shadow_person values(self)
returning make_ref(shadow_person, object_id) into v_ref_person;
self.a_student := new student(v_ref_person);
RETURN;
END;
This seems to work, but probably has really horrible side-affects that nobody would want in a real production environment.
Here's the full script:
drop type base_object force;
drop type student force;
drop type person force;
drop table shadow_person;
create or replace type base_object is object (a varchar2(10)) not final;
/
CREATE OR REPLACE TYPE PERSON FORCE AUTHID DEFINER UNDER BASE_OBJECT (
b varchar2(10),
CONSTRUCTOR FUNCTION PERSON RETURN SELF AS RESULT
) NOT FINAL;
/
CREATE OR REPLACE TYPE STUDENT FORCE AUTHID DEFINER UNDER BASE_OBJECT (
c varchar2(10),
a_person REF PERSON,
CONSTRUCTOR FUNCTION STUDENT(p_person ref PERSON) RETURN SELF AS RESULT
) NOT FINAL;
/
alter type person add attribute a_student student cascade;
create table shadow_person of person;
CREATE OR REPLACE TYPE BODY PERSON
AS
CONSTRUCTOR FUNCTION PERSON
RETURN SELF AS RESULT IS
v_ref_person ref person;
BEGIN
insert into shadow_person values(self)
returning make_ref(shadow_person, object_id) into v_ref_person;
self.a_student := new student(v_ref_person);
RETURN;
END;
END;
/
CREATE OR REPLACE TYPE BODY STUDENT
AS
CONSTRUCTOR FUNCTION STUDENT(p_person REF PERSON)
RETURN SELF AS RESULT IS
BEGIN
self.a_person := p_person;
RETURN;
END;
END;
/
--Example of how to use it:
declare
v_person person := person;
begin
v_person.a := 'person a';
v_person.b := 'b';
v_person.a_student.a := 'student a';
v_person.a_student.c := 'c';
dbms_output.put_line(v_person.a_student.c);
end;
/