Anydata and Collections 20188367001

Anydata and Collections

Steven Feuerstein has written a PLSQL-utility str2list in which he uses dynamic sql to fill collections of different types.
While I was playing with the “new” Oracle types ANYTYPE, ANYDATA and ANYDATSET I found that the ANYDATA type can be used to do something simular.

So I have written a function which accepts a string and a delimiter, and returns the string split in several parts in an ANYDATA which can be deposited in a collection of different types.

create or replace function str2list
  ( str   in varchar2
  , delim in varchar2 := ';'
  )
return anydata
is
  v_endloc   pls_integer;
  v_startloc pls_integer;
  ad  anydata;
  mt  anytype;
begin
  if str is null
  then
    return null;
  end if;
  anytype.BeginCreate( DBMS_TYPES.TYPECODE_TABLE, mt );
  mt.setinfo( null, null, null, null, null, null, DBMS_TYPES.TYPECODE_VARCHAR2, 0 );
  mt.EndCreate;
  anydata.begincreate( mt, ad );
--
  v_startloc := 1;
  loop
    v_endloc := instr( str, delim, v_startloc );
    if v_endloc > 0
    then
      ad.setvarchar2( substr( str, v_startloc, v_endloc - v_startloc ) );
      v_startloc := v_endloc + 1;
    else
      ad.setvarchar2( substr( str, v_startloc ), true );
      exit;
    end if;
  end loop;
  ad.endcreate;
  return ad;
end;

And to show the use of this function:

create or replace type anton1 is table of varchar2(20);

create or replace type anton4 is varray(5) of varchar2(20);

declare
  type anton2 is table of varchar2(20) index by binary_integer;
  type anton3 is table of varchar2(20);
  a1 anton1;
  a2 anton2;
  a3 anton3;
  a4 anton4;
  r pls_integer;
  ind pls_integer;
begin
  r := str2list('amis;is;great').getCollection( a1 );
  ind := a1.first;
  while ind is not null
  loop
    dbms_output.put_line( 'nested table type: ' || ind || ' = ' || a1(ind) );
    ind := a1.next( ind );
  end loop;
--
  r := str2list('amis;is;great').getCollection( a2 );
  ind := a2.first;
  while ind is not null
  loop
    dbms_output.put_line( 'index by table: ' || ind || ' = ' || a2(ind) );
    ind := a2.next( ind );
  end loop;
--
  r := str2list('amis;is;great').getCollection( a3 );
  ind := a3.first;
  while ind is not null
  loop
    dbms_output.put_line( 'nested table: ' || ind || ' = ' || a3(ind) );
    ind := a3.next( ind );
  end loop;
--
  r := str2list('amis;is;great').getCollection( a4 );
  ind := a4.first;
  while ind is not null
  loop
    dbms_output.put_line( 'varray: ' || ind || ' = ' || a4(ind) );
    ind := a4.next( ind );
  end loop;
--
end;

nested table type: 1 = amis
nested table type: 2 = is
nested table type: 3 = great
index by table: 0 = amis
index by table: 1 = is
index by table: 2 = great
nested table: 1 = amis
nested table: 2 = is
nested table: 3 = great
varray: 1 = amis
varray: 2 = is
varray: 3 = great

PL/SQL procedure successfully completed.

This demonstrates that it is possible to cast the ANYDATA to all different collections type, so I wonder why it is not possible to do the inverse. Casting the PLSQL collection types (the index-by table and the PLSQL nested table) to an ANYDATA raises
ORA-22370: incorrect usage of method ORA-22370: incorrect usage of method ConvertCollection
ORA-06512: at “SYS.ANYDATA”, line 63
ORA-06512: at line 70

Anton