2012-04-19 25 views
7

私はANYDATAに格納されているユーザー定義のオブジェクトを処理するプロシージャを作成しています。オブジェクト型と属性名は実行時にしか知ることができないので、declareセクションでそれを定義することはできません。 Javaでは、私はそれに対処するために反射を使用することができます、私はクラス名とフィールド名を知ることができます。その後、私はリフレクションを通してフィールドにアクセスできます。そのようなPLSQLでそれを行う方法はありますか?私の頭の中では、プロシージャ内にSQL文字列を動的に作成して実行しています。しかし、それは私が正確にしたいものではありません。PLSQLのリフレクション?

たとえば、ユーザーAはADTタイプをcreate or replace type Person_type as object (fname varchar2(10), lname varchar2(10));と定義し、オブジェクトインスタンスを作成してANYDATAに挿入します。

私の手順では、何とか私はこのオブジェクトの最初の属性であるfnameを処理する必要があることを知っています。

declare 
    adobject A.Person_type; -- HERE! I don't know the type yet, so I can't define adobject! 
    tempAnydata anydata; 
    rt number; 
    vbuffer varchar2(10); 
    ... 
begin 
    select somecolumn 
    into tempAnydata 
    from sometable 
    where something='something' for update; 

    rt := tempAnydata.GetObject(adobject); 

    vbuffer := adobject.fname; -- HERE! I don't know the attribute name is fname! 
    -- deal with vbuffer here 
end; 

だから私は動的にそれを作るために何をすべき:最初の場所でのADTの種類を知っているのであれば、私のコードは次のようになりますか?前もって感謝します。

+0

あなたは 'tempAnydata'があることがわかっている場合は*本当に*' A.person_type'あなたはきっと(まさにこのタイプのadobjectとそうでない場合は、あなたが 'のGetObject(adobjectを行うことができませんでした)')そうであるようにその型の最初の属性が何であるかも知っています。または私は何かを逃していますか? –

+0

A.person_typeは単なる例であり、任意のユーザー定義タイプとすることができます。それはB.anymal_typeなのかもしれません。 – icespace

+1

静的なタイピングは大変です。 (ちょっと古いスモールトークカーがさまよって、自己に呟く:-) –

答えて

7

ANYDATAについては、ANYTYPEを使用して、タイプが正しいことを確認する必要があります。次に、piecewisegetVarchar2を使用して属性にアクセスできます。

以下のコードの大部分は型のチェック用ですが、型の安全性を心配していない場合は不要です。

create or replace function get_first_attribute(
    p_anydata in out anydata --note the "out" - this is required for the "piecewise" 
) return varchar2 is 
    v_typecode pls_integer; 
    v_anytype anytype; 
begin 
    --Get the typecode, and the ANYTYPE 
    v_typecode := p_anydata.getType(v_anytype); 

    --Check that it's really an object 
    if v_typecode = dbms_types.typecode_object then 
     --If it is an object, find the first item 
     declare 
      v_first_attribute_typecode pls_integer; 
      v_aname   varchar2(32767); 
      v_result   pls_integer; 
      v_varchar  varchar2(32767); 
      --Variables we don't really care about, but need for function output 
      v_prec   pls_integer; 
      v_scale   pls_integer; 
      v_len   pls_integer; 
      v_csid   pls_integer; 
      v_csfrm   pls_integer; 
      v_attr_elt_type anytype; 
     begin 
      v_first_attribute_typecode := v_anytype.getAttrElemInfo(
       pos   => 1, --First attribute 
       prec   => v_prec, 
       scale   => v_scale, 
       len   => v_len, 
       csid   => v_csid, 
       csfrm   => v_csfrm, 
       attr_elt_type => v_attr_elt_type, 
       aname   => v_aname); 

      --Check typecode of attribute 
      if v_first_attribute_typecode = dbms_types.typecode_varchar2 then 
       --Now that we've verified the type, get the actual value. 
       p_anydata.piecewise; 
       v_result := p_anydata.getVarchar2(c => v_varchar); 

       --DEBUG: Print the attribute name, in case you're curious 
       --dbms_output.put_line('v_aname: '||v_aname); 

       return v_varchar; 
      else 
       raise_application_error(-20000, 'Unexpected 1st Attribute Typecode: '|| 
        v_first_attribute_typecode); 
      end if; 
     end; 
    else 
     raise_application_error(-20000, 'Unexpected Typecode: '||v_typecode); 
    end if; 
end; 
/

タイプ:

create or replace type Person_type as object (fname varchar2(10), lname varchar2(10)); 

create or replace type other_type as object (first_name varchar2(10), poetry clob); 

テストの実行:

declare 
    --Create records 
    v_type1 person_type := person_type('Ford', 'Prefect'); 
    v_type2 other_type := other_type('Paula', 'blah blah...'); 
    v_anydata anydata; 
begin 
    --Convert to ANYDATA. 
    --Works as long as ANYDATA is an object with a varchar2 as the first attribute. 
    v_anydata := anydata.convertObject(v_type1); 
    dbms_output.put_line(get_first_attribute(v_anydata)); 

    v_anydata := anydata.convertObject(v_type2); 
    dbms_output.put_line(get_first_attribute(v_anydata)); 
end; 
/

出力

関数は値を戻します:

Ford 
Paula 
+0

+1 - 私は私の答えを削除します。私はまだOPのアーキテクチャーが特有のものだと思っていますが、本当に駄目なら、これは正しい解決策です – APC

+0

@APC私はあなたの答えを保つべきだと思います。私はオブジェクトリレーショナルソリューションをANYDATAよりも頻繁に見てきました。 (一般的に私はそれらの両方を避けようとしていますが、私はいつも過度のジェネリックなソリューションに少し疑念を抱いています) –

+0

すごい!非常にありがとう、jonearles。それは本当に私が欲しいものです! ANYTYPE、お会いできてうれしいです。 – icespace