Der normale Fall sieht dabei wie folgt aus:
Man erstellt einen Objekt-Typ und gibt die Attribute mit Namen und Typ an.
create type val_t as object ( v1 number, v2 number, v3 number ); /Jetzt fehlt noch der Table-Typ von dem gerade erstellen Objekt-Typ.
create type val_tab as table of val_t; /Die Table-Function soll nun das Einmaleins bis 3 ausgeben.
create or replace function multiplication_table return val_tab pipelined is v_column_count integer := 3; begin for i in 1..v_column_count loop pipe row ( val_t (i*1,i*2,i*3) ); end loop; return; end multiplication_table;Soweit so gut, jedoch wollen wir auch das Einmaleins bis 5, 10, 100 oder einer anderen natürlichen Zahl n, ohne dafür jeweils eine eigene Table Function samt den notwendigen Objekt-Typen erstellen zu wollen.
Dazu sind einige Funktionen zu implementieren, welche es erlauben, den Rückgabetyp dynamisch zu erstellen. Für die Aufgabe ergibt sich folgenden Struktur:
create or replace type multiplication_table as object ( v_row_types anytype, v_column_count integer, v_rows_processed integer, static function show_table( p_column_count_in in integer ) return anydataset pipelined using multiplication_table, static function ODCITableDescribe( rtype out anytype, p_column_count_in in integer ) return number, static function ODCITablePrepare( sctx out multiplication_table, tf_info SYS.ODCITabFuncInfo, p_column_count_in in integer ) return number, static function ODCITableStart( sctx in out multiplication_table, p_column_count_in in integer ) return number, member function ODCITableFetch( self in out multiplication_table, nrows in number, rws out anydataset ) return number, member function ODCITableClose( self in multiplication_table ) return number );Dabei wird der Rückgabetyp durch die Funktion
ODCITableDescribe
beschrieben, also die Anzahl und Typen der Attribute festgelegt. Konkret für die Lösung der Aufgabe bedeutet dies, das für das Einmaleins bis n auch n Attribute vorhanden sein müssen. Die Funktion ODCITableFetch
liefert dann die Zeilen zurück, indem die Bestandteile des Objekt-Typs mit Werten gefüllt werden.create or replace type body multiplication_table as static function ODCITableDescribe( rtype out anytype, p_column_count_in in integer ) return number as v_record_structure anytype; begin anytype.begincreate(dbms_types.typecode_object, v_record_structure); for i in 1 .. p_column_count_in loop v_record_structure.addattr( ANAME => '#' || to_char(i), TYPECODE => dbms_types.typecode_number, PREC => null, SCALE => null, LEN => null, CSID => null, CSFRM => null, ATTR_TYPE => null ); end loop; v_record_structure.endcreate(); anytype.begincreate(dbms_types.typecode_table, rtype); rtype.setinfo( null, null, null, null, null, v_record_structure, dbms_types.typecode_object, 0); rtype.endcreate(); return odciconst.success; end ODCITableDescribe; static function ODCITablePrepare( sctx out multiplication_table, tf_info SYS.ODCITabFuncInfo, p_column_count_in in integer ) return number as prec pls_integer; scale pls_integer; len pls_integer; csid pls_integer; csfrm pls_integer; record_desc anytype; aname varchar2(30); dummy pls_integer; begin dummy := tf_info.RetType.GetAttrElemInfo( null, prec, scale, len, csid, csfrm, record_desc, aname); sctx := multiplication_table(record_desc, p_column_count_in, 0); return odciconst.success; end ODCITablePrepare; static function ODCITableStart( sctx in out multiplication_table, p_column_count_in in integer ) return number as begin return odciconst.success; end ODCITableStart; member function ODCITableFetch( self in out multiplication_table, nrows in number, rws out anydataset ) return number as begin rws := null; if (self.v_rows_processed < self.v_column_count) then self.v_rows_processed := self.v_rows_processed + 1; anydataset.begincreate(dbms_types.typecode_object, self.v_row_types, rws); rws.addinstance; rws.piecewise(); for i in 1 .. self.v_column_count loop rws.setnumber(self.v_rows_processed * i); end loop; rws.endcreate; end if; return odciconst.success; end ODCITableFetch; member function ODCITableClose( self in multiplication_table ) return number as begin return odciconst.success; end ODCITableClose; end;Ein Aufruf mit dem Argument 4 liefert dann:
select * from table(multiplication_table.show_table(4));
#1 #2 #3 #4 ------- ------- ------- ------- 1 2 3 4 2 4 6 8 3 6 9 12 4 8 12 16Während die Wahl des Arguments 6 einen Objekt-Typ mit zwei zusätzlichen Spalten zur Folge hat:
select * from table(multiplication_table.show_table(6));
#1 #2 #3 #4 #5 #6 ------- ------- ------- ------- ------- ------- 1 2 3 4 5 6 2 4 6 8 10 12 3 6 9 12 15 18 4 8 12 16 20 24 5 10 15 20 25 30 6 12 18 24 30 36Weitere Informationen dazu findet man im Data Cartridge Developer's Guide.
Keine Kommentare:
Kommentar veröffentlichen