oracleoracle19c

Get UDT type name inside of its body in Oracle 19c


Recently I've bumped into a case when I needed to get a UDT name inside of its body. I've managed to come to the following solution:

  not final instantiable member function get_type_name
    return varchar2
  is
    l_type_name varchar2(200);
  begin
    l_type_name := sys.anydata.convertObject(self).GetTypeName();
    l_type_name := replace(l_type_name, sys_context('userenv', 'current_schema') || '.');
    return l_type_name;
  end;

So it returns object name without owner schema.

But it looks a little bit weird to use anydata only to get a type name. Maybe I am missing some magic method in self reference? Looked through Oracle documentation but no luck so far.

If you know any more "natural" options please share.


Solution

  • Objects are an awkward afterthought in Oracle databases, so there aren't very many good functions for examining them.

    One option is using the call stack to look at the name of the currently executing program (aka the type). There's 2 ways of doing that, which I'll show below.

    The only other way I can think of to get the type name is using sys_typeid(), which requires an execute immediate.

    CREATE TYPE mytype AS OBJECT (
        type_name VARCHAR2(30),
        CONSTRUCTOR FUNCTION mytype(SELF IN OUT NOCOPY mytype) RETURN SELF AS RESULT
    ) NOT FINAL;
    /
    
    CREATE or replace TYPE BODY mytype AS
        CONSTRUCTOR FUNCTION mytype(SELF IN OUT NOCOPY mytype) RETURN SELF AS RESULT IS
        BEGIN
            -- option 1 - call stack
            SELF.type_name := utl_call_stack.subprogram(1)(1);
            -- option 2 - using $$plsql_unit "conditional compilation flag"
            SELF.type_name := $$plsql_unit;
            -- option 3
            execute immediate 'select type_name from user_types where typeid = sys_typeid(:a)' into SELF.type_name using self;
            -- or your way: 
            SELF.type_name := replace(sys.anydata.convertObject(self).GetTypeName(), sys_context('userenv', 'current_schema') || '.');
            RETURN;
        END;
    END;
    /
    
    select (new mytype()).type_name from dual;
    

    I don't think any of these are very "natural" or intuitive at all. So the ANYDATA solution seems fine to me.