26 メタデータAPIの使用

DBMS_METADATA APIにより、オブジェクト・メタデータをチェックおよび更新できます。

DBMS_METADATA APIを使用すると、次の操作を行うことができます。

  • オブジェクトのメタデータのXMLとしての取得

  • SQL DDLへの変換を含む様々な方法でのXMLの変換

  • 取得で抽出したオブジェクトを再作成するためのXMLの送信

DBMS_METADATA_DIFF APIを使用すると、データベース間でオブジェクトを比較し、同じ型のオブジェクトのうち時間の経過によってメタデータが変化したものを識別できます。

26.1 DBMS_METADATA APIを使用する理由

DBMS_METADATA APIを使用すると、メタデータを抽出するために独自のコードを記述して管理する必要がなくなります。

独自のコードをOracle Databaseで開発して、ディクショナリからメタデータを抽出したり、メタデータを操作(列の追加、列のデータ型の変更など)したり、メタデータをDDLに変換して同じまたは別のデータベースでオブジェクトを再作成できるようにする場合、メンテナンスが問題になります。ディクショナリの新機能をサポートするよう、そのコードを更新された状態に保つことは困難です。

Oracle Databaseでは、ディクショナリ・メタデータの抽出、操作および再作成に関する集中的な機能が提供されます。また、Oracle Databaseでは、すべてのディクショナリ・オブジェクトを最新のレベルでサポートしています。

DBMS_METADATA APIは、記述および管理するカスタム・コードの量を大幅に削減しますが、通常のデータベース手順の変更はありません。DBMS_METADATA APIはデータ・ディクショナリ・ビューと同様に、データベースのインストール時にcatproc.sqlを実行し、SQLスクリプトを実行することでインストールできます。DBMS_METADATAをインストールすると、制限モードであっても、インスタンスが動作中はいつでも使用可能です。

DBMS_METADATA APIを使用してデータベースのリリースを変更する場合、ソースコードを変更する必要はありません。DBMS_METADATA APIを使用すると、異なるOracle Databaseリリース間でコードに上位互換性を持たせることができます。1つのリリースで取得したXML文書を、同じまたはそれ以上のリリースの送信インタフェースで処理できます。たとえば、Oracle Database 10gリリース2 (10.2)データベースで取得したXML文書は、Oracle Database 12cに送信できます。

26.2 DBMS_METADATA APIの概要

DBMS_METADATA API機能を利用する方法を学習します。

DBMS_METADATA APIにおいては、データベース内のすべてのエンティティは、オブジェクト型に属するオブジェクトとして形成されています。たとえば、表scott.empはオブジェクトです。オブジェクト・タイプはTABLEです。オブジェクトのメタデータをフェッチする場合は、オブジェクト型を指定する必要があります。

フィルタを使用したオブジェクト・タイプ別のオブジェクトの検索

オブジェクト型の特定のオブジェクトまたは一連のオブジェクトをフェッチするには、フィルタを指定します。各オブジェクト型に対して異なるフィルタが定義されます。たとえば、TABLEオブジェクト型に対して定義されている2つのフィルタはSCHEMAおよびNAMEです。これらのフィルタにより、たとえば、スキーマがscott、名前がempの表が必要であることを表現できます。

DBMS_METADATA APIは、XML(Extensible Markup Language)およびXSLT(Extensible Stylesheet Language Transformation)を使用します。XMLは解析や変換が容易な汎用形式であるため、DBMS_METADATA APIは、オブジェクト・メタデータをXMLとして表現します。DBMS_METADATA APIは、XSLTを使用してXML文書を他のXML文書またはSQL DDLのいずれかに変換します。

DBMS_METADATA APIを使用して、メタデータをフェッチするとき(または再送信するとき)に、1つ以上の変換(XSLTスクリプト)をXMLに適用するよう指定できます。APIには、XML文書をSQL作成DDLに変換する名前付きDDL以外にも、いくつかの事前定義変換があります。

次に変換パラメータを使用して、変換の条件を指定できます。また、オブジェクトのメタデータの特定の属性にアクセスするために、オプションの解析項目も指定できます。

ビューを使用した有効なDBMS_METADATAオプションの確認

次のビューを使用して、各オブジェクト型変換、各変換のパラメータおよびその解析項目に使用できるDBMS_METADATA変換を確認できます。

  • DBMS_METADATA_TRANSFORMS - DBMS_METADATAパッケージで使用されるすべての有効なOracle提供の変換を示します。

  • DBMS_METADATA_TRANSFORM_PARAMS - 各変換について有効な変換パラメータを示します。

  • DBMS_METADATA_PARSE_ITEMS - 有効な解析項目を示します。

たとえば、INDEXオブジェクトに使用できる変換を確認するとします。次の問合せは、INDEXオブジェクトに対して有効な変換、必要な入力型および結果の出力型を返します。

SQL> SELECT transform, output_type, input_type, description
2 FROM dbms_metadata_transforms
3 WHERE object_type='INDEX';


TRANSFORM  OUTPUT_TYP INPUT_TYPE           DESCRIPTION
---------- ---------- -------------------- ----------------------------------------------------------------------
ALTERXML   ALTER_XML  SXML difference doc  Generate ALTER_XML from SXML difference document
SXMLDDL    DDL        SXML                 Convert SXML to DDL
MODIFY     XML        XML                  Modify XML document according to transform parameters
SXML       SXML       XML                  Convert XML to SXML
DDL        DDL        XML                  Convert XML to SQL to create the object
ALTERDDL   ALTER_DDL  ALTER_XML            Convert ALTER_XML to ALTER_DDL
MODIFYSXML SXML       SXML                 Modify SXML document

DDL変換に有効な変換パラメータを知る必要がある場合は、次の問合せを実行できます。

SQL> SELECT param, datatype, default_val, description
2 FROM dbms_metadata_transform_params
3 WHERE object_type='INDEX' and transform='DDL'
4 ORDER BY param;


PARAM                     DATATYPE   DEFAULT_VA  DESCRIPTION
------------------------- ---------- ----------  ----------------------------------------------------------------------
INCLUDE_PARTITIONS        TEXT                   Include generated interval and list partitions in DDL 
                                                      transformation
INDEX_COMPRESSION_CLAUSE  TEXT       ""          Text of user-specified index compression clause
PARTITIONING              BOOLEAN    TRUE        Include partitioning clauses in transformation
PARTITION_NAME            TEXT       ""          Name of partition selected for the transformation
PCTSPACE                  NUMBER     ""          Percentage by which space allocation is to be modified
SEGMENT_ATTRIBUTES        BOOLEAN    TRUE        Include segment attribute clauses (physical attributes, storage 
                                                      attribues, tablespace, logging) in transformation
STORAGE                   BOOLEAN    TRUE        Include storage clauses in transformation
SUBPARTITION_NAME         TEXT       ""          Name of subpartition selected for the transformation
TABLESPACE                BOOLEAN    TRUE        Include tablespace clauses in transformation

INDEXオブジェクト型に関する特定のメタデータを返す次の問合せを実行することもできます。

SQL> SELECT parse_item, description 
2 FROM dbms_metadata_parse_items 
3 WHERE object_type='INDEX' and convert='Y';

PARSE_ITEM           DESCRIPTION
-------------------- --------------------------------------------------------------
OBJECT_TYPE          Object type
TABLESPACE           Object tablespace (default tablespace for partitioned objects)
BASE_OBJECT_SCHEMA   Schema of the base object
SCHEMA               Object schema, if any
NAME                 Object name
BASE_OBJECT_NAME     Name of the base object
BASE_OBJECT_TYPE     Object type of the base object
SYSTEM_GENERATED     Y = system-generated object; N = not system-generated

26.3 オブジェクトのメタデータを取得するためのDBMS_METADATA APIの使用

DBMS_METADATA APIの取得インタフェースでは、取得するオブジェクトの種類を指定できます。

26.3.1 オブジェクトのメタデータを取得するためのDBMS_METADATA APIの使用方法

問合せ可能なOracle Databaseオブジェクトの種類について学習し、問合せに使用するインタフェースを決定します。

種類は、特定のオブジェクト型(表、索引、プロシージャなど)または論理単位を形成する異なるオブジェクト型のコレクション(データベース・エクスポート、スキーマ・エクスポートなど)のいずれかです。デフォルトでは、フェッチされたメタデータがXML文書に返されます。

ノート:

スキーマにないオブジェクトにアクセスするには、SELECT_CATALOG_ROLEロールが必要です。ただし、ロールは多くのPL/SQLオブジェクト(ストアド・プロシージャ、ファンクション、定義者権限API)内で無効とされます。そのため、他のスキーマのオブジェクト(一般的には、SELECT_CATALOG_ROLEロールを必要とするすべてのオブジェクト)内にアクセスするPL/SQLプログラムを記述する場合は、実行者権限APIにコードを入力する必要があります。

プログラム・インタフェースを使用して、簡単な参照を実行したり、アプリケーションを開発できます。システム・メタデータの簡単な問合せを行う場合は、ブラウザ・インタフェースを使用できます。アプリケーションの一部として、ディクショナリ・メタデータを抽出する場合は、プログラム・インタフェースを使用できます。その場合、同じことをするために現在使用しているSQLスクリプトまたはカスタマイズしたコードを使用するかわりに、DBMS_METADATA APIで提供されているプロシージャを使用することもできます。

26.3.2 基本的なメタデータ取得の通常ステップ

メタデータを取得する場合は、DBMS_METADATA PL/SQL APIを使用します。

次に、プログラム・インタフェースおよびブラウザ・インタフェースの例を示します。

DBMS_METADATAプログラム・インタフェースの例では、DBMS_METADATAプログラム・インタフェースを使用して1つの表のメタデータを取得する基本的な方法を説明します。この例では、get_table_mdというファンクションを作成するDBMS_METADATAプログラムを作成します。ファンクションは、1つの表のメタデータを返します。

DBMS_METADATAブラウザ・インタフェースの例では、ブラウザ・インタフェースを使用して同じ結果を得る方法を説明します。

例26-1 データ取得のためのDBMS_METADATAプログラム・インタフェースの使用

  1. hrスキーマ内の1つの表(timecards)のメタデータを返すファンクションget_table_mdを作成するDBMS_METADATAプログラムを作成します。プログラムの内容は次のようになります。(この例ではプログラムにmetadata_program.sqlという名前を付けます)。

    CREATE OR REPLACE FUNCTION get_table_md RETURN CLOB IS
    -- Define local variables.
    h NUMBER; --handle returned by OPEN
    th NUMBER; -- handle returned by ADD_TRANSFORM
    doc CLOB;
    BEGIN
    
    -- Specify the object type.
    h := DBMS_METADATA.OPEN('TABLE');
    
    -- Use filters to specify the particular object desired.
    DBMS_METADATA.SET_FILTER(h,'SCHEMA','HR');
    DBMS_METADATA.SET_FILTER(h,'NAME','TIMECARDS');
    
     -- Request that the metadata be transformed into creation DDL.
    th := DBMS_METADATA.ADD_TRANSFORM(h,'DDL');
    
     -- Fetch the object.
    doc := DBMS_METADATA.FETCH_CLOB(h);
    
     -- Release resources.
    DBMS_METADATA.CLOSE(h);
    RETURN doc;
    END;
    / 
    
  2. ユーザーhrとして接続します。

  3. プログラムを実行してget_table_mdファンクションを作成します。

    SQL> @metadata_program

  4. 新しく作成したget_table_mdファンクションを選択操作で使用します。完全で中断のない出力を生成するには、問合せの実行前に、次のとおり、PAGESIZEを0(ゼロ)にし、またLONGを大きい数に設定します。

    SQL> SET PAGESIZE 0
    SQL> SET LONG 1000000
    SQL> SELECT get_table_md FROM dual;
    
  5. hrスキーマのtimecards表のメタデータを示す出力は、次のようになります。

      CREATE TABLE "HR"."TIMECARDS"
       (    "EMPLOYEE_ID" NUMBER(6,0),
            "WEEK" NUMBER(2,0),
            "JOB_ID" VARCHAR2(10),
            "HOURS_WORKED" NUMBER(4,2),
             FOREIGN KEY ("EMPLOYEE_ID")
              REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ENABLE
       ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
      STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
      PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
      TABLESPACE "EXAMPLE"
    

例26-2 データ取得のためのDBMS_METADATAブラウザ・インタフェースの使用

SQL> SET PAGESIZE 0
SQL> SET LONG 1000000
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','TIMECARDS','HR') FROM dual;

この問合せの結果は、DBMS_METADATAプログラム・インタフェースの例のステップ5で示された結果と同じです。

26.3.3 複数のオブジェクトの取得

複数オブジェクトの取得例および説明。

前の例「データ取得のためのDBMS_METADATAプログラム・インタフェースの使用」では、オブジェクトが1つしか存在しないことがわかっていたため、FETCH_CLOBプロシージャは1回のみコールされました。scottスキーマのすべての表などの複数のオブジェクトも取得できます。それを行うには、次の構成メンバーを使用する必要があります。

  LOOP
    doc := DBMS_METADATA.FETCH_CLOB(h);
    --
    -- When there are no more objects to be retrieved, FETCH_CLOB returns NULL.
    --
    EXIT WHEN doc IS NULL;
  END LOOP;

次の例に、構成メンバーの使用および複数のオブジェクトの取得を示します。この例では、ユーザーscottとして接続します。パスワードは、tigerです。

例26-3 複数のオブジェクトの取得

  1. 次のように、my_metadataという名前の表と、get_tables_mdという名前のプロシージャを作成します。すべてのオブジェクトを返すことはできないため、それらを表に格納して最後に問合せを実行します。

    DROP TABLE my_metadata;
    CREATE TABLE my_metadata (md clob);
    CREATE OR REPLACE PROCEDURE get_tables_md IS
    -- Define local variables
    h       NUMBER;         -- handle returned by 'OPEN'
    th      NUMBER;         -- handle returned by 'ADD_TRANSFORM'
    doc     CLOB;           -- metadata is returned in a CLOB
    BEGIN
    
     -- Specify the object type.
     h := DBMS_METADATA.OPEN('TABLE');
    
     -- Use filters to specify the schema.
     DBMS_METADATA.SET_FILTER(h,'SCHEMA','SCOTT');
    
     -- Request that the metadata be transformed into creation DDL.
     th := DBMS_METADATA.ADD_TRANSFORM(h,'DDL');
    
     -- Fetch the objects.
     LOOP
       doc := DBMS_METADATA.FETCH_CLOB(h);
    
      -- When there are no more objects to be retrieved, FETCH_CLOB returns NULL.
       EXIT WHEN doc IS NULL;
    
       -- Store the metadata in a table.
       INSERT INTO my_metadata(md) VALUES (doc);
       COMMIT;
     END LOOP;
     
     -- Release resources.
     DBMS_METADATA.CLOSE(h);
    END;
    /
    
  2. 次のようにプロシージャを実行します。

    EXECUTE get_tables_md;
    
  3. my_metadata表を問い合せて、取得された内容を確認します。

    SET LONG 9000000
    SET PAGES 0
    SELECT * FROM my_metadata;

26.3.4 変換の条件指定

DBMS_METADATAを使用して追加する変換の条件を指定するには、変換パラメータを使用できます。

変換パラメータを使用するには、SET_TRANSFORM_PARAMプロシージャを使用します。たとえば、TABLEオブジェクトに対してDDL変換を追加した場合、SEGMENT_ATTRIBUTES変換パラメータを指定して、物理、ストレージ、ロギングなどのセグメント属性をDDLに表示しないようにすることができます。デフォルトでは、セグメント属性がDDLに表示されます。

例26-4 変換の条件指定

この例では、SET_TRANSFORM_PARAMプロシージャの使用方法を示します。

  1. 次のように、get_table_mdという名前のファンクションを作成します。

    CREATE OR REPLACE FUNCTION get_table_md RETURN CLOB IS
     -- Define local variables.
     h    NUMBER;   -- handle returned by 'OPEN'
     th   NUMBER;   -- handle returned by 'ADD_TRANSFORM'
     doc  CLOB;
    BEGIN
    
     -- Specify the object type. 
     h := DBMS_METADATA.OPEN('TABLE');
    
     -- Use filters to specify the particular object desired.
     DBMS_METADATA.SET_FILTER(h,'SCHEMA','HR');
     DBMS_METADATA.SET_FILTER(h,'NAME','TIMECARDS');
    
     -- Request that the metadata be transformed into creation DDL.
     th := dbms_metadata.add_transform(h,'DDL');
    
     -- Specify that segment attributes are not to be returned.
     -- Note that this call uses the TRANSFORM handle, not the OPEN handle.
    DBMS_METADATA.SET_TRANSFORM_PARAM(th,'SEGMENT_ATTRIBUTES',false);
    
     -- Fetch the object.
     doc := DBMS_METADATA.FETCH_CLOB(h);
    
     -- Release resources.
     DBMS_METADATA.CLOSE(h);
    
     RETURN doc;
    END;
    /
    
  2. 次の問合せを実行します。

    SQL> SELECT get_table_md FROM dual;
    

    出力は、次のようになります。

      CREATE TABLE "HR"."TIMECARDS"
       (    "EMPLOYEE_ID" NUMBER(6,0),
            "WEEK" NUMBER(2,0),
            "JOB_ID" VARCHAR2(10),
            "HOURS_WORKED" NUMBER(4,2),
             FOREIGN KEY ("EMPLOYEE_ID")
              REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ENABLE
       )
    

ここまでの例ではDDL変換という1つの変換を使用しました。DBMS_METADATA APIでは、最初の出力が2番目の入力になり、2番目の出力が3番目の入力になるというように、複数の変換を指定することもできます。

Oracleには、XML文書を変更するMODIFYと呼ばれる変換があります。スキーマ名や表領域名の変更などが行えます。これには、再マップ・パラメータおよびSET_REMAP_PARAMプロシージャを使用します。

例26-5 XML文書の変更

この例では、SET_REMAP_PARAMプロシージャの使用方法を示します。まずMODIFY変換を追加し、再マップ・パラメータを指定して、スキーマ名をhrからscottに変更します。次にDDL変換を追加します。MODIFY変換の出力は、DDL変換への入力となるXML文書です。最終的な結果は、timecards表の作成DDLであり、hrスキーマのすべてのインスタンスはscottに変更されます。

  1. 次のように、remap_schemaという名前のファンクションを作成します。

    CREATE OR REPLACE FUNCTION remap_schema RETURN CLOB IS
    -- Define local variables.
    h NUMBER; --handle returned by OPEN
    th NUMBER; -- handle returned by ADD_TRANSFORM
    doc CLOB;
    BEGIN
    
    -- Specify the object type.
    h := DBMS_METADATA.OPEN('TABLE');
    
    -- Use filters to specify the particular object desired.
    DBMS_METADATA.SET_FILTER(h,'SCHEMA','HR');
    DBMS_METADATA.SET_FILTER(h,'NAME','TIMECARDS');
    
    -- Request that the schema name be modified.
    th := DBMS_METADATA.ADD_TRANSFORM(h,'MODIFY');
    DBMS_METADATA.SET_REMAP_PARAM(th,'REMAP_SCHEMA','HR','SCOTT');
    
    -- Request that the metadata be transformed into creation DDL.
    th := DBMS_METADATA.ADD_TRANSFORM(h,'DDL');
    
    -- Specify that segment attributes are not to be returned.
    DBMS_METADATA.SET_TRANSFORM_PARAM(th,'SEGMENT_ATTRIBUTES',false);
    
    -- Fetch the object.
    doc := DBMS_METADATA.FETCH_CLOB(h);
    
    -- Release resources.
    DBMS_METADATA.CLOSE(h);
    RETURN doc;
    END;
    / 
    
  2. 次の問合せを実行します。

    SELECT remap_schema FROM dual;
    

    出力は、次のようになります。

      CREATE TABLE "SCOTT"."TIMECARDS"
       (    "EMPLOYEE_ID" NUMBER(6,0),
            "WEEK" NUMBER(2,0),
            "JOB_ID" VARCHAR2(10),
            "HOURS_WORKED" NUMBER(4,2),
             FOREIGN KEY ("EMPLOYEE_ID")
              REFERENCES "SCOTT"."EMPLOYEES" ("EMPLOYEE_ID") ENABLE
       )
    

    XSLTをよく理解しているユーザーであれば、独自の変換を追加してXMLを処理できます。

例26-6 INCLUDE_SHARDING_CLAUSES、およびPARTITION BYまたはPARTITIONS AUTOキーワード

Oracle Database 23c以降では、dbms_metedata.set_transform_param()を使用してAPI変換パラメータINCLUDE_SHARDING_CLAUSESを設定できます。TRUEに設定した場合は、get_ddl()により、次に説明するようにシャード構文が生成されます。

SHARDEDキーワードを指定した作成:

次の例では、キーワードcustomersを使用してシャード表が作成されます。

CREATE SHARDED TABLE customers (
   custno   NUMBER NOT NULL,
   region  char(2) NOT NULL,
   name  VARCHAR2(20),
   zip number)
PARTITION BY CONSISTENT HASH (custno, region)
PARTITIONS AUTO
TABLESPACE SET ts1;

INCLUDE_SHARDING_CLAUSESパラメータをFALSEに設定した場合、DDLにはPARTITION BY RANGEが含まれ、PARTITIONS AUTO句は含まれません。例:

コンシステント・ハッシュによるパーティション:

CREATE SHARDED TABLE customers (
   custno   NUMBER NOT NULL,
   region  char(2) NOT NULL,
   name  VARCHAR2(20),
   zip number)
PARTITION BY CONSISTENT HASH (custno, region)
PARTITIONS AUTO
TABLESPACE SET ts1;

26.3.5 特定のメタデータ属性へのアクセス

DBMS_METADATA APIを使用してオブジェクトのメタデータの特定のメタデータ属性にアクセスする方法を示します。

名前やスキーマなどのオブジェクトのメタデータの特定の属性へアクセスすることが必要な場合もあります。属性の情報は返されたメタデータを解析して取得できますが、DBMS_METADATA APIには、別の機能もあります。メタデータから解析され、別のデータ構造に返される特定の属性を解析項目に指定できます。これを行うには、SET_PARSE_ITEMプロシージャを使用します。

例26-7 特定のメタデータ属性にアクセスするための解析項目の使用

この例では、スキーマ内のすべての表をチェックする方法を示します。各表では、名前を取得するために解析項目を使用します。次に表のすべての索引を取得するために名前を使用します。この例では、sys.ku$_ddlsオブジェクトのメタデータを返すFETCH_DDLファンクションの使用方法を確認できます。

この例では、いくつかの表および索引を含むスキーマに接続していることとします。この一連のステップの結果によって、my_metadataという名前の表が作成されます。

  1. 次のように、my_metadataという名前の表と、get_tables_and_indexesという名前のプロシージャを作成します。

    DROP TABLE my_metadata;
    CREATE TABLE my_metadata (
      object_type   VARCHAR2(30),
      name          VARCHAR2(30),
      md            CLOB);
    CREATE OR REPLACE PROCEDURE get_tables_and_indexes IS
    -- Define local variables.
    h1      NUMBER;         -- handle returned by OPEN for tables
    h2      NUMBER;         -- handle returned by OPEN for indexes
    th1     NUMBER;         -- handle returned by ADD_TRANSFORM for tables
    th2     NUMBER;         -- handle returned by ADD_TRANSFORM for indexes
    doc     sys.ku$_ddls;   -- metadata is returned in sys.ku$_ddls,
                            --  a nested table of sys.ku$_ddl objects
    ddl     CLOB;           -- creation DDL for an object
    pi      sys.ku$_parsed_items;   -- parse items are returned in this object
                                    -- which is contained in sys.ku$_ddl
    objname VARCHAR2(30);   -- the parsed object name
    idxddls sys.ku$_ddls;   -- metadata is returned in sys.ku$_ddls,
                            --  a nested table of sys.ku$_ddl objects
    idxname VARCHAR2(30);   -- the parsed index name
    BEGIN
     -- This procedure has an outer loop that fetches tables,
     -- and an inner loop that fetches indexes.
     
     -- Specify the object type: TABLE.
     h1 := DBMS_METADATA.OPEN('TABLE');
     
     -- Request that the table name be returned as a parse item.
     DBMS_METADATA.SET_PARSE_ITEM(h1,'NAME');
     
     -- Request that the metadata be transformed into creation DDL.
     th1 := DBMS_METADATA.ADD_TRANSFORM(h1,'DDL');
     
     -- Specify that segment attributes are not to be returned.
     DBMS_METADATA.SET_TRANSFORM_PARAM(th1,'SEGMENT_ATTRIBUTES',false);
     
     -- Set up the outer loop: fetch the TABLE objects.
     LOOP
       doc := dbms_metadata.fetch_ddl(h1);
     
    -- When there are no more objects to be retrieved, FETCH_DDL returns NULL.
       EXIT WHEN doc IS NULL;
     
    -- Loop through the rows of the ku$_ddls nested table.
       FOR i IN doc.FIRST..doc.LAST LOOP
         ddl := doc(i).ddlText;
         pi := doc(i).parsedItems;
         -- Loop through the returned parse items.
         IF pi IS NOT NULL AND pi.COUNT > 0 THEN
           FOR j IN pi.FIRST..pi.LAST LOOP
             IF pi(j).item='NAME' THEN
               objname := pi(j).value;
             END IF;
           END LOOP;
         END IF;
         -- Insert information about this object into our table.
         INSERT INTO my_metadata(object_type, name, md)
           VALUES ('TABLE',objname,ddl);
         COMMIT;
       END LOOP;
     
       -- Now fetch indexes using the parsed table name as
       --  a BASE_OBJECT_NAME filter.
     
       -- Specify the object type.
       h2 := DBMS_METADATA.OPEN('INDEX');
     
       -- The base object is the table retrieved in the outer loop.
       DBMS_METADATA.SET_FILTER(h2,'BASE_OBJECT_NAME',objname);
     
       -- Exclude system-generated indexes.
       DBMS_METADATA.SET_FILTER(h2,'SYSTEM_GENERATED',false);
     
       -- Request that the index name be returned as a parse item.
       DBMS_METADATA.SET_PARSE_ITEM(h2,'NAME');
     
       -- Request that the metadata be transformed into creation DDL.
       th2 := DBMS_METADATA.ADD_TRANSFORM(h2,'DDL');
     
       -- Specify that segment attributes are not to be returned.
       DBMS_METADATA.SET_TRANSFORM_PARAM(th2,'SEGMENT_ATTRIBUTES',false);
      
     
       LOOP
        idxddls := dbms_metadata.fetch_ddl(h2);
     
        -- When there are no more objects to  be retrieved, FETCH_DDL returns NULL.
        EXIT WHEN idxddls IS NULL;
     
          FOR i in idxddls.FIRST..idxddls.LAST LOOP
            ddl := idxddls(i).ddlText;
            pi  := idxddls(i).parsedItems;
            -- Loop through the returned parse items.
            IF pi IS NOT NULL AND pi.COUNT > 0 THEN
              FOR j IN pi.FIRST..pi.LAST LOOP
                IF pi(j).item='NAME' THEN
                  idxname := pi(j).value;
                END IF;
              END LOOP;
             END IF;
       
             -- Store the metadata in our table.
              INSERT INTO my_metadata(object_type, name, md)
                VALUES ('INDEX',idxname,ddl);
             COMMIT;
           END LOOP;  -- for loop
      END LOOP;
      DBMS_METADATA.CLOSE(h2);
     END LOOP;
     DBMS_METADATA.CLOSE(h1);
    END;
    /
    
  2. 次のようにプロシージャを実行します。

    EXECUTE get_tables_and_indexes;
    
  3. 次の問合せを実行して、取得された内容を確認します。

    SET LONG 9000000
    SET PAGES 0
    SELECT * FROM my_metadata;

26.4 取得したオブジェクトを再作成するためのDBMS_METADATA APIの使用

オブジェクトに対しメタデータをフェッチする場合、そのメタデータを使用して、オブジェクトを異なるデータベースまたはスキーマで再作成することを選択できます。

メタデータをフェッチする際に、再マッピングの決定を行う準備ができておらず、その決定を先送りにするとします。再マッピングに関する決定を先送りにするには、メタデータをXMLとしてフェッチし、ファイルまたは表に格納します。後で、そのファイルまたは表を送信インタフェースで使用して、オブジェクトを再作成できます。

送信インタフェースは取得インタフェースに類似した構成です。送信インタフェースには、作成するオブジェクトのオブジェクト型を指定するOPENWプロシージャが存在します。変換の指定、パラメータの変換および項目の解析ができます。CONVERTファンクションをコールしてXMLからDDLに変換する、またはPUTファンクションをコールしてXMLをDDLに変換し、DDLを送信してオブジェクトを作成できます。

例26-8 取得したオブジェクトを再作成するための送信インタフェースの使用

この例は、1つのスキーマの表のXMLをフェッチし、次に送信インタフェースを使用して別のスキーマの表を再作成する方法を示します。

  1. 次のように、権限を持つユーザーとして接続します。

    CONNECT system
    Enter password: password
    
  2. 別のスキーマ内のオブジェクトにアクセスするにはSELECT_CATALOG_ROLEロールが必要であるため、実行者の権限パッケージを作成してプロシージャを保持します。定義者権限PL/SQLオブジェクト(プロシージャ、ファンクションなど)では、ロールは使用できません。

    CREATE OR REPLACE PACKAGE example_pkg AUTHID current_user IS
      PROCEDURE move_table(
            table_name  in VARCHAR2,
            from_schema in VARCHAR2,
            to_schema   in VARCHAR2 );
    END example_pkg;
    /
    CREATE OR REPLACE PACKAGE BODY example_pkg IS
    PROCEDURE move_table(
            table_name  in VARCHAR2,
            from_schema in VARCHAR2,
            to_schema   in VARCHAR2 ) IS
    
    -- Define local variables.
    h1      NUMBER;         -- handle returned by OPEN
    h2      NUMBER;         -- handle returned by OPENW
    th1     NUMBER;         -- handle returned by ADD_TRANSFORM for MODIFY
    th2     NUMBER;         -- handle returned by ADD_TRANSFORM for DDL
    xml     CLOB;           -- XML document
    errs    sys.ku$_SubmitResults := sys.ku$_SubmitResults();
    err     sys.ku$_SubmitResult;
    result  BOOLEAN;
    BEGIN
    
    -- Specify the object type.
    h1 := DBMS_METADATA.OPEN('TABLE');
    
    -- Use filters to specify the name and schema of the table.
    DBMS_METADATA.SET_FILTER(h1,'NAME',table_name);
    DBMS_METADATA.SET_FILTER(h1,'SCHEMA',from_schema);
    
    -- Fetch the XML.
    xml := DBMS_METADATA.FETCH_CLOB(h1);
    IF xml IS NULL THEN
        DBMS_OUTPUT.PUT_LINE('Table ' || from_schema || '.' || table_name
    || ' not found');
        RETURN;
      END IF;
    
    -- Release resources.
    DBMS_METADATA.CLOSE(h1);
    
    -- Use the submit interface to re-create the object in another schema.
    
    -- Specify the object type using OPENW (instead of OPEN).
    h2 := DBMS_METADATA.OPENW('TABLE');
    
    -- First, add the MODIFY transform.
    th1 := DBMS_METADATA.ADD_TRANSFORM(h2,'MODIFY');
    
    -- Specify the desired modification: remap the schema name.
    DBMS_METADATA.SET_REMAP_PARAM(th1,'REMAP_SCHEMA',from_schema,to_schema);
    
    -- Now add the DDL transform so that the modified XML can be
    --  transformed into creation DDL.
    th2 := DBMS_METADATA.ADD_TRANSFORM(h2,'DDL');
    
    -- Call PUT to re-create the object.
    result := DBMS_METADATA.PUT(h2,xml,0,errs);
    
    DBMS_METADATA.CLOSE(h2);
      IF NOT result THEN
        -- Process the error information.
        FOR i IN errs.FIRST..errs.LAST LOOP
          err := errs(i);
          FOR j IN err.errorLines.FIRST..err.errorLines.LAST LOOP
            dbms_output.put_line(err.errorLines(j).errorText);
          END LOOP;
        END LOOP;
      END IF;
    END;
    END example_pkg;
    /
    
  3. 次に、次のように、スキーマSCOTTmy_exampleという名前の表を作成します。

    CONNECT scott
    Enter password:
    -- The password is tiger.
    
    DROP TABLE my_example;
    CREATE TABLE my_example (a NUMBER, b VARCHAR2(30));
    
    CONNECT system
    Enter password: password
    
    SET LONG 9000000
    SET PAGESIZE 0
    SET SERVEROUTPUT ON SIZE 100000
    
  4. 次のように、my_example表をSYSTEMスキーマにコピーします。

    DROP TABLE my_example;
    EXECUTE example_pkg.move_table('MY_EXAMPLE','SCOTT','SYSTEM');
    
  5. 次の問合せを実行して、正しく動作したことを確認します。

    SELECT DBMS_METADATA.GET_DDL('TABLE','MY_EXAMPLE') FROM dual;

26.5 異なるオブジェクト型のコレクションを取得するためのDBMS_METADATA APIの使用

異なる型のオブジェクトであるにもかかわらず1つの論理単位を構成しているオブジェクトのコレクションを取得するには、DBMS_METADATA APIで異種オブジェクト型を使用します。

異なる型のオブジェクトであるにもかかわらず、1つの論理単位を形成するOracle Databaseオブジェクトのコレクションを取得する必要がある場合があります。たとえば、データベースまたはスキーマのすべてのオブジェクト、または表および依存する索引、制約、権限付与、監査などすべてを取得する必要があるとします。DBMS_METADATA APIでは、こうした取得を可能にするために、複数の異種オブジェクト型を提供しています。異種オブジェクト型は、オブジェクト型の順序付けられた集合です。

Oracleでは、次の異種オブジェクト型を提供しています。

  • TABLE_EXPORT - 表およびその依存オブジェクト

  • SCHEMA_EXPORT - スキーマおよびその内容

  • DATABASE_EXPORT - データベース内のオブジェクト

これらのオブジェクト型は、Oracle Data Pump Exportユーティリティで使用するために開発されましたが、ユーザー独自のアプリケーションでも使用できます。

これらの型では、ブラウザ・インタフェースまたは送信インタフェースではなく、プログラム取得インタフェース(OPEN, FETCH, CLOSE)のみが使用できます。

同種型と同様に、異種オブジェクト型に対してもフィルタを指定できます。たとえば、TABLE_EXPORTに対してSCHEMAおよびNAMEフィルタを指定でき、SCHEMA_EXPORTに対してSCHEMAフィルタを指定できます。

例26-9 異種オブジェクト型の取得方法

この例は、scottスキーマ内のオブジェクト型を取得する方法を示します。ユーザーscottとして接続します。パスワードは、tigerです。

  1. 取得したオブジェクトを格納するための表を作成します。

    DROP TABLE my_metadata;
    CREATE TABLE my_metadata (md CLOB);
    CREATE OR REPLACE PROCEDURE get_schema_md IS
    
    -- Define local variables.
    h       NUMBER;         -- handle returned by OPEN
    th      NUMBER;         -- handle returned by ADD_TRANSFORM
    doc     CLOB;           -- metadata is returned in a CLOB
    BEGIN
    
    -- Specify the object type.
     h := DBMS_METADATA.OPEN('SCHEMA_EXPORT');
    
     -- Use filters to specify the schema.
     DBMS_METADATA.SET_FILTER(h,'SCHEMA','SCOTT');
    
     -- Request that the metadata be transformed into creation DDL.
     th := DBMS_METADATA.ADD_TRANSFORM(h,'DDL');
    
     -- Fetch the objects.
     LOOP
       doc := DBMS_METADATA.FETCH_CLOB(h);
    
       -- When there are no more objects to be retrieved, FETCH_CLOB returns NULL.
       EXIT WHEN doc IS NULL;
    
       -- Store the metadata in the table.
       INSERT INTO my_metadata(md) VALUES (doc);
       COMMIT;
     END LOOP;
     
     -- Release resources.
     DBMS_METADATA.CLOSE(h);
    END;
    /
    
  2. 次のようにプロシージャを実行します。

    EXECUTE get_schema_md;
    
  3. 次の問合せを実行して、取得された内容を確認します。

    SET LONG 9000000
    SET PAGESIZE 0
    SELECT * FROM my_metadata;
    

この例では、オブジェクトは、オブジェクト型による順序で返されます。たとえば、すべての表が返され、次に表のすべての権限が返され、次に表のすべての索引が返されます。順序は一般的に有効な作成順序となります。このため、返された順序でオブジェクトを取得し、送信インタフェースを使用して別のスキーマまたはデータベースで同じ順序で再作成した場合、通常、エラーは発生しません。(通常、例外は、循環参照の場合に発生します。たとえば、パッケージAにパッケージBへのコールが含まれ、パッケージBにパッケージAへのコールが含まれる場合、2回目にいずれかのパッケージを再コンパイルする必要があります。)

26.6 異種オブジェクト型の戻り値のフィルタ

SET_FILTERプロシージャを使用して異機種間オブジェクト・タイプの戻り値をフィルタできるようにする方法を学習します。

返されるオブジェクトに対して、より詳細な制御を行うには、SET_FILTERプロシージャを使用して特定のメンバー型にのみフィルタを適用するよう指定します。これを行うには、SET_FILTERの4つ目のパラメータとして、メンバー型のパス名を指定します。また、EXCLUDE_PATH_EXPRフィルタを使用して、オブジェクト型のすべてのオブジェクトを除外できます。有効なパス名のリストは、TABLE_EXPORT_OBJECTSカタログ・ビューを参照してください。

例26-10 異種オブジェクト型の戻り値のフィルタ

この例では、SET_FILTERを使用して、返されるオブジェクトに対するより詳細な制御を指定します。

  1. 取得したオブジェクトを格納する表my_metadataを作成し、プロシージャget_schema_md2を作成します:

    DROP TABLE my_metadata;
    CREATE TABLE my_metadata (md CLOB);
    CREATE OR REPLACE PROCEDURE get_schema_md2 IS
    
    -- Define local variables.
    h       NUMBER;         -- handle returned by 'OPEN'
    th      NUMBER;         -- handle returned by 'ADD_TRANSFORM'
    doc     CLOB;           -- metadata is returned in a CLOB
    BEGIN
    
     -- Specify the object type.
     h := DBMS_METADATA.OPEN('SCHEMA_EXPORT');
    
     -- Use filters to specify the schema.
     DBMS_METADATA.SET_FILTER(h,'SCHEMA','SCOTT');
    
     -- Use the fourth parameter to SET_FILTER to specify a filter
     -- that applies to a specific member object type.
     DBMS_METADATA.SET_FILTER(h,'NAME_EXPR','!=''MY_METADATA''','TABLE');
    
     -- Use the EXCLUDE_PATH_EXPR filter to exclude procedures.
     DBMS_METADATA.SET_FILTER(h,'EXCLUDE_PATH_EXPR','=''PROCEDURE''');
    
     -- Request that the metadata be transformed into creation DDL.
     th := DBMS_METADATA.ADD_TRANSFORM(h,'DDL');
    
     -- Use the fourth parameter to SET_TRANSFORM_PARAM to specify a parameter
     --  that applies to a specific member object type.
    DBMS_METADATA.SET_TRANSFORM_PARAM(th,'SEGMENT_ATTRIBUTES',false,'TABLE');
    
     -- Fetch the objects.
     LOOP
       doc := dbms_metadata.fetch_clob(h);
    
       -- When there are no more objects to be retrieved, FETCH_CLOB returns NULL.
       EXIT WHEN doc IS NULL;
    
       -- Store the metadata in the table.
       INSERT INTO my_metadata(md) VALUES (doc);
       COMMIT;
     END LOOP;
     
     -- Release resources.
     DBMS_METADATA.CLOSE(h);
    END;
    /
    
  2. プロシージャを実行します:

    EXECUTE get_schema_md2;
    
  3. 次の問合せを実行して、取得された内容を確認します。

    SET LONG 9000000
    SET PAGESIZE 0
    SELECT * FROM my_metadata;

26.7 オブジェクトのメタデータを比較するためのDBMS_METADATA_DIFF APIの使用

DBMS_METADATAおよびDBMS_METADATA_DIFFの取得インタフェース、比較インタフェースおよび送信インタフェースの説明および使用例。この例では、2つの表のメタデータをフェッチして比較し、1つの表を他方と同じ内容に変更するALTER文を生成します。

わかりやすくするために、この例全体でファンクションの変形を使用しています。

例26-11 オブジェクト・メタデータの比較

  1. 次のように、2つの表TAB1TAB2を作成します。

    SQL> CREATE TABLE TAB1
      2     (    "EMPNO" NUMBER(4,0),
      3          "ENAME" VARCHAR2(10),
      4          "JOB" VARCHAR2(9),
      5          "DEPTNO" NUMBER(2,0)
      6     ) ;
     
    Table created.
     
    SQL> CREATE TABLE TAB2
      2     (    "EMPNO" NUMBER(4,0) PRIMARY KEY ENABLE,
      3          "ENAME" VARCHAR2(20),
      4          "MGR" NUMBER(4,0),
      5          "DEPTNO" NUMBER(2,0)
      6     ) ;
     
    Table created.
     

    TAB1TAB2の差異に注意します。

    • 表名が異なります。

    • TAB2には主キー制約がありますが、TAB1にはありません。

    • それぞれの表で、ENAME列の長さが異なります。

    • TAB1にはJOB列がありますが、TAB2にはありません。

    • TAB2にはMGR列がありますが、TAB1にはありません。

  2. SXML形式の表メタデータを返すファンクションを作成します。DBMS_METADATA_DIFF APIを使用するときに、SXMLに関して注意する必要がある重要な点について示します。

    • SXMLはオブジェクト・メタデータのXML表現です。

    • 返されるSXMLは、DBMS_METADATA.GET_XMLによって返されるXMLと同じではありません。その場合のXMLは、複雑かつ不透明であり、バイナリ値やインスタンス固有の値などが含まれます。

    • SXMLは、SQL作成DDLを直接XMLに変換したものと考えることができます。タグ名と構造は、『Oracle Database SQL言語リファレンス』で説明されている名前に対応しています。

    • SXMLは、編集と比較を行えるように設計されています。

    ここでは例を単純にするため、変換パラメータを使用して物理プロパティを抑止します。

    SQL> CREATE OR REPLACE FUNCTION get_table_sxml(name IN VARCHAR2) RETURN CLOB IS
      2   open_handle NUMBER;
      3   transform_handle NUMBER;
      4   doc CLOB;
      5  BEGIN
      6   open_handle := DBMS_METADATA.OPEN('TABLE');
      7   DBMS_METADATA.SET_FILTER(open_handle,'NAME',name);
      8   --
      9   -- Use the 'SXML' transform to convert XML to SXML
     10   --
     11   transform_handle := DBMS_METADATA.ADD_TRANSFORM(open_handle,'SXML');
     12   --
     13   -- Use this transform parameter to suppress physical properties
     14   --
     15   DBMS_METADATA.SET_TRANSFORM_PARAM(transform_handle,'PHYSICAL_PROPERTIES',
     16                                     FALSE);
     17   doc := DBMS_METADATA.FETCH_CLOB(open_handle);
     18   DBMS_METADATA.CLOSE(open_handle);
     19   RETURN doc;
     20  END;
     21  /
     
    Function created.
     
  3. 次のように、get_table_sxmlファンクションを使用して、2つの表の表SXMLをフェッチします。

    SQL> SELECT get_table_sxml('TAB1') FROM dual;
     
      <TABLE xmlns="http://xmlns.oracle.com/ku" version="1.0">
       <SCHEMA>SCOTT</SCHEMA>
       <NAME>TAB1</NAME>
       <RELATIONAL_TABLE>
          <COL_LIST>
             <COL_LIST_ITEM>
                <NAME>EMPNO</NAME>
                <DATATYPE>NUMBER</DATATYPE>
                <PRECISION>4</PRECISION>
                <SCALE>0</SCALE>
             </COL_LIST_ITEM>
             <COL_LIST_ITEM>
                <NAME>ENAME</NAME>
                <DATATYPE>VARCHAR2</DATATYPE>
                <LENGTH>10</LENGTH>
             </COL_LIST_ITEM>
             <COL_LIST_ITEM>
                <NAME>JOB</NAME>
                <DATATYPE>VARCHAR2</DATATYPE>
                <LENGTH>9</LENGTH>
             </COL_LIST_ITEM>
             <COL_LIST_ITEM>
                <NAME>DEPTNO</NAME>
                <DATATYPE>NUMBER</DATATYPE>
                <PRECISION>2</PRECISION>
                <SCALE>0</SCALE>
             </COL_LIST_ITEM>
          </COL_LIST>
       </RELATIONAL_TABLE>
    </TABLE> 
      
    1 row selected.
     
    SQL> SELECT get_table_sxml('TAB2') FROM dual;
     
      <TABLE xmlns="http://xmlns.oracle.com/ku" version="1.0">
       <SCHEMA>SCOTT</SCHEMA>
       <NAME>TAB2</NAME>
       <RELATIONAL_TABLE>
          <COL_LIST>
             <COL_LIST_ITEM>
                <NAME>EMPNO</NAME>
                <DATATYPE>NUMBER</DATATYPE>
                <PRECISION>4</PRECISION>
                <SCALE>0</SCALE>
             </COL_LIST_ITEM>
             <COL_LIST_ITEM>
                <NAME>ENAME</NAME>
                <DATATYPE>VARCHAR2</DATATYPE>
                <LENGTH>20</LENGTH>
             </COL_LIST_ITEM>
             <COL_LIST_ITEM>
                <NAME>MGR</NAME>
                <DATATYPE>NUMBER</DATATYPE>
                <PRECISION>4</PRECISION>
                <SCALE>0</SCALE>
             </COL_LIST_ITEM>
             <COL_LIST_ITEM>
                <NAME>DEPTNO</NAME>
                <DATATYPE>NUMBER</DATATYPE>
                <PRECISION>2</PRECISION>
                <SCALE>0</SCALE>
             </COL_LIST_ITEM>
          </COL_LIST>
          <PRIMARY_KEY_CONSTRAINT_LIST>
             <PRIMARY_KEY_CONSTRAINT_LIST_ITEM>
                <COL_LIST>
                   <COL_LIST_ITEM>
                      <NAME>EMPNO</NAME>
                   </COL_LIST_ITEM>
                </COL_LIST>
             </PRIMARY_KEY_CONSTRAINT_LIST_ITEM>
          </PRIMARY_KEY_CONSTRAINT_LIST>
       </RELATIONAL_TABLE>
    </TABLE> 
     
    1 row selected.
     
  4. 次のように、DBMS_METADATAブラウザAPIを使用して結果を比較します。

    SQL> SELECT dbms_metadata.get_sxml('TABLE','TAB1') FROM dual;
    SQL> SELECT dbms_metadata.get_sxml('TABLE','TAB2') FROM dual;
    
  5. DBMS_METADATA_DIFF APIを使用してファンクションを作成し、2つの表のメタデータを比較します。このファンクションでは、ステップ2で定義したget_table_sxmlファンクションを使用します。

    SQL> CREATE OR REPLACE FUNCTION compare_table_sxml(name1 IN VARCHAR2,
      2                                          name2 IN VARCHAR2) RETURN CLOB IS
      3   doc1 CLOB;
      4   doc2 CLOB;
      5   diffdoc CLOB;
      6   openc_handle NUMBER;
      7  BEGIN
      8   --
      9   -- Fetch the SXML for the two tables
     10   --
     11   doc1 := get_table_sxml(name1);
     12   doc2 := get_table_sxml(name2);
     13   --
     14   -- Specify the object type in the OPENC call
     15   --
     16   openc_handle := DBMS_METADATA_DIFF.OPENC('TABLE');
     17   --
     18   -- Add each document
     19   --
     20   DBMS_METADATA_DIFF.ADD_DOCUMENT(openc_handle,doc1);
     21   DBMS_METADATA_DIFF.ADD_DOCUMENT(openc_handle,doc2);
     22   --
     23   -- Fetch the SXML difference document
     24   --
     25   diffdoc := DBMS_METADATA_DIFF.FETCH_CLOB(openc_handle);
     26   DBMS_METADATA_DIFF.CLOSE(openc_handle);
     27   RETURN diffdoc;
     28  END;
     29  /
     
    Function created.
    
  6. 次のようにファンクションを使用して、2つの表のSXML差分ドキュメントをフェッチします。

    SQL> SELECT compare_table_sxml('TAB1','TAB2') FROM dual;
    
    <TABLE xmlns="http://xmlns.oracle.com/ku" version="1.0">
      <SCHEMA>SCOTT</SCHEMA>
      <NAME value1="TAB1">TAB2</NAME>
      <RELATIONAL_TABLE>
        <COL_LIST>
          <COL_LIST_ITEM>
            <NAME>EMPNO</NAME>
            <DATATYPE>NUMBER</DATATYPE>
            <PRECISION>4</PRECISION>
            <SCALE>0</SCALE>
          </COL_LIST_ITEM>
          <COL_LIST_ITEM>
            <NAME>ENAME</NAME>
            <DATATYPE>VARCHAR2</DATATYPE>
            <LENGTH value1="10">20</LENGTH>
          </COL_LIST_ITEM>
          <COL_LIST_ITEM src="1">
            <NAME>JOB</NAME>
            <DATATYPE>VARCHAR2</DATATYPE>
            <LENGTH>9</LENGTH>
          </COL_LIST_ITEM>
          <COL_LIST_ITEM>
            <NAME>DEPTNO</NAME>
            <DATATYPE>NUMBER</DATATYPE>
            <PRECISION>2</PRECISION>
            <SCALE>0</SCALE>
          </COL_LIST_ITEM>
          <COL_LIST_ITEM src="2">
            <NAME>MGR</NAME>
            <DATATYPE>NUMBER</DATATYPE>
            <PRECISION>4</PRECISION>
            <SCALE>0</SCALE>
          </COL_LIST_ITEM>
        </COL_LIST>
        <PRIMARY_KEY_CONSTRAINT_LIST src="2">
          <PRIMARY_KEY_CONSTRAINT_LIST_ITEM>
            <COL_LIST>
              <COL_LIST_ITEM>
                <NAME>EMPNO</NAME>
              </COL_LIST_ITEM>
            </COL_LIST>
          </PRIMARY_KEY_CONSTRAINT_LIST_ITEM>
        </PRIMARY_KEY_CONSTRAINT_LIST>
      </RELATIONAL_TABLE>
    </TABLE>
     
    1 row selected.
     

    SXML差分ドキュメントでは、2つのSXMLドキュメントの結合内容が示され、差分を識別するXML属性value1およびsrcが使用されます。ある要素が1つのドキュメントのみに存在するときは、その要素がsrcでマーキングされます。したがって、<COL_LIST_ITEM src="1">は、この要素が最初のドキュメント(TAB1)に含まれていて、2番目のドキュメントに含まれていないことを表します。ある要素が両方のドキュメントに存在し、値がそれぞれ異なる場合、この要素の値は2番目のドキュメント内の値とされ、value1によって最初のドキュメント内のその値が示されます。たとえば、<LENGTH value1="10">20</LENGTH>は、長さがTAB1(最初のドキュメント)では10、TAB2では20であることを表します。

  7. 次のように、DBMS_METADATA_DIFFブラウザAPIを使用して、結果を比較します。

    SQL> SELECT dbms_metadata_diff.compare_sxml('TABLE','TAB1','TAB2') FROM dual;
    
  8. DBMS_METADATA.CONVERT APIを使用してファンクションを作成し、ALTERXMLドキュメントを生成します。これは、片方のオブジェクトをもう一方のオブジェクトと同様にするためのALTER文が含まれているXML文書です。解析項目を使用して、個々のALTER文に関する情報を取得することもできます。(この例ではこれまでに定義したファンクションを使用しています。)

    SQL> CREATE OR REPLACE FUNCTION get_table_alterxml(name1 IN VARCHAR2,
      2                                           name2 IN VARCHAR2) RETURN CLOB IS
      3   diffdoc CLOB;
      4   openw_handle NUMBER;
      5   transform_handle NUMBER;
      6   alterxml CLOB;
      7  BEGIN
      8   --
      9   -- Use the function just defined to get the difference document
     10   --
     11   diffdoc := compare_table_sxml(name1,name2);
     12   --
     13   -- Specify the object type in the OPENW call
     14   --
     15   openw_handle := DBMS_METADATA.OPENW('TABLE');
     16   --
     17   -- Use the ALTERXML transform to generate the ALTER_XML document
     18   --
     19   transform_handle := DBMS_METADATA.ADD_TRANSFORM(openw_handle,'ALTERXML');
     20   --
     21   -- Request parse items
     22   --
     23   DBMS_METADATA.SET_PARSE_ITEM(openw_handle,'CLAUSE_TYPE');
     24   DBMS_METADATA.SET_PARSE_ITEM(openw_handle,'NAME');
     25   DBMS_METADATA.SET_PARSE_ITEM(openw_handle,'COLUMN_ATTRIBUTE');
     26   --
     27   -- Create a temporary LOB
     28   --
     29   DBMS_LOB.CREATETEMPORARY(alterxml, TRUE );
     30   --
     31   -- Call CONVERT to do the transform
     32   --
     33   DBMS_METADATA.CONVERT(openw_handle,diffdoc,alterxml);
     34   --
     35   -- Close context and return the result
     36   --
     37   DBMS_METADATA.CLOSE(openw_handle);
     38   RETURN alterxml;
     39  END;
     40  /
     
    Function created.
    
  9. 次のようにファンクションを使用して、ALTER_XML文書をフェッチします。

    SQL> SELECT get_table_alterxml('TAB1','TAB2') FROM dual;
     
    <ALTER_XML xmlns="http://xmlns.oracle.com/ku" version="1.0">
       <OBJECT_TYPE>TABLE</OBJECT_TYPE>
       <OBJECT1>
          <SCHEMA>SCOTT</SCHEMA>
          <NAME>TAB1</NAME>
       </OBJECT1>
       <OBJECT2>
          <SCHEMA>SCOTT</SCHEMA>
          <NAME>TAB2</NAME>
       </OBJECT2>
       <ALTER_LIST>
          <ALTER_LIST_ITEM>
             <PARSE_LIST>
                <PARSE_LIST_ITEM>
                   <ITEM>NAME</ITEM>
                   <VALUE>MGR</VALUE>
                </PARSE_LIST_ITEM>
                <PARSE_LIST_ITEM>
                   <ITEM>CLAUSE_TYPE</ITEM>
                   <VALUE>ADD_COLUMN</VALUE>
                </PARSE_LIST_ITEM>
             </PARSE_LIST>
             <SQL_LIST>
                <SQL_LIST_ITEM>
                   <TEXT>ALTER TABLE "SCOTT"."TAB1" ADD ("MGR" NUMBER(4,0))</TEXT>
                </SQL_LIST_ITEM>
             </SQL_LIST>
          </ALTER_LIST_ITEM>
          <ALTER_LIST_ITEM>
             <PARSE_LIST>
                <PARSE_LIST_ITEM>
                   <ITEM>NAME</ITEM>
                   <VALUE>JOB</VALUE>
                </PARSE_LIST_ITEM>
                <PARSE_LIST_ITEM>
                   <ITEM>CLAUSE_TYPE</ITEM>
                   <VALUE>DROP_COLUMN</VALUE>
                </PARSE_LIST_ITEM>
             </PARSE_LIST>
             <SQL_LIST>
                <SQL_LIST_ITEM>
                   <TEXT>ALTER TABLE "SCOTT"."TAB1" DROP ("JOB")</TEXT>
                </SQL_LIST_ITEM>
             </SQL_LIST>
          </ALTER_LIST_ITEM>
          <ALTER_LIST_ITEM>
             <PARSE_LIST>
                <PARSE_LIST_ITEM>
                   <ITEM>NAME</ITEM>
                   <VALUE>ENAME</VALUE>
                </PARSE_LIST_ITEM>
                <PARSE_LIST_ITEM>
                   <ITEM>CLAUSE_TYPE</ITEM>
                   <VALUE>MODIFY_COLUMN</VALUE>
                </PARSE_LIST_ITEM>
                <PARSE_LIST_ITEM>
                   <ITEM>COLUMN_ATTRIBUTE</ITEM>
                   <VALUE> SIZE_INCREASE</VALUE>
                </PARSE_LIST_ITEM>
             </PARSE_LIST>
             <SQL_LIST>
                <SQL_LIST_ITEM>
                   <TEXT>ALTER TABLE "SCOTT"."TAB1" MODIFY 
                        ("ENAME" VARCHAR2(20))
                   </TEXT>
                </SQL_LIST_ITEM>
             </SQL_LIST>
          </ALTER_LIST_ITEM>
          <ALTER_LIST_ITEM>
             <PARSE_LIST>
                <PARSE_LIST_ITEM>
                   <ITEM>CLAUSE_TYPE</ITEM>
                   <VALUE>ADD_CONSTRAINT</VALUE>
                </PARSE_LIST_ITEM>
             </PARSE_LIST>
             <SQL_LIST>
                <SQL_LIST_ITEM>
                   <TEXT>ALTER TABLE "SCOTT"."TAB1" ADD  PRIMARY KEY
                         ("EMPNO") ENABLE
                   </TEXT>
                </SQL_LIST_ITEM>
             </SQL_LIST>
          </ALTER_LIST_ITEM>
          <ALTER_LIST_ITEM>
             <PARSE_LIST>
                <PARSE_LIST_ITEM>
                   <ITEM>NAME</ITEM>
                   <VALUE>TAB1</VALUE>
                </PARSE_LIST_ITEM>
                <PARSE_LIST_ITEM>
                   <ITEM>CLAUSE_TYPE</ITEM>
                   <VALUE>RENAME_TABLE</VALUE>
                </PARSE_LIST_ITEM>
             </PARSE_LIST>
             <SQL_LIST>
                <SQL_LIST_ITEM>
                   <TEXT>ALTER TABLE "SCOTT"."TAB1" RENAME TO "TAB2"</TEXT>
                </SQL_LIST_ITEM>
             </SQL_LIST>
          </ALTER_LIST_ITEM>
       </ALTER_LIST>
    </ALTER_XML>
     
     
    1 row selected.
     
  10. 次のように、DBMS_METADATA_DIFFブラウザAPIを使用して、結果を比較します。

    SQL> SELECT dbms_metadata_diff.compare_alter_xml('TABLE','TAB1','TAB2') FROM dual;
    
  11. ALTER_XML文書には、それぞれの変更のALTER_LISTが含まれています。それぞれのALTER_LIST_ITEMには、名前と値のペアとしての解析項目が含まれたPARSE_LISTと、特定の変更のSQLが含まれたSQL_LISTがあります。PARSE_LIST内の情報を使用してこの文書を解析し、どのSQL文を実行するかを決定できます。(たとえば、この場合は、変更の1つがDROP_COLUMNであり、それを実行しないことを決定できます。)

  12. 次のように、DBMS_METADATA.CONVERT APIおよびALTER DDL変換を使用する最後の1つのファンクションを作成して、ALTER_XML文書をSQL DDLに変換します。

    SQL> CREATE OR REPLACE FUNCTION get_table_alterddl(name1 IN VARCHAR2,
      2                                           name2 IN VARCHAR2) RETURN CLOB IS
      3   alterxml CLOB;
      4   openw_handle NUMBER;
      5   transform_handle NUMBER;
      6   alterddl CLOB;
      7  BEGIN
      8   --
      9   -- Use the function just defined to get the ALTER_XML document
     10   --
     11   alterxml := get_table_alterxml(name1,name2);
     12   --
     13   -- Specify the object type in the OPENW call
     14   --
     15   openw_handle := DBMS_METADATA.OPENW('TABLE');
     16   --
     17   -- Use ALTERDDL transform to convert the ALTER_XML document to SQL DDL
     18   -- 
     19   transform_handle := DBMS_METADATA.ADD_TRANSFORM(openw_handle,'ALTERDDL');
     20   --
     21   -- Use the SQLTERMINATOR transform parameter to append a terminator
     22   -- to each SQL statement
     23   --
     24   DBMS_METADATA.SET_TRANSFORM_PARAM(transform_handle,'SQLTERMINATOR',true);
     25   --
     26   -- Create a temporary lob
     27   --
     28   DBMS_LOB.CREATETEMPORARY(alterddl, TRUE );
     29   --
     30   -- Call CONVERT to do the transform
     31   --
     32   DBMS_METADATA.CONVERT(openw_handle,alterxml,alterddl);
     33   --
     34   -- Close context and return the result
     35   --
     36   DBMS_METADATA.CLOSE(openw_handle);
     37   RETURN alterddl;
     38  END;
     39  /
     
    Function created.
     
  13. 次のようにファンクションを使用して、SQL ALTER文をフェッチします。

    SQL> SELECT get_table_alterddl('TAB1','TAB2') FROM dual;
    ALTER TABLE "SCOTT"."TAB1" ADD ("MGR" NUMBER(4,0))
    /
      ALTER TABLE "SCOTT"."TAB1" DROP ("JOB")
    /
      ALTER TABLE "SCOTT"."TAB1" MODIFY ("ENAME" VARCHAR2(20))
    /
      ALTER TABLE "SCOTT"."TAB1" ADD  PRIMARY KEY ("EMPNO") ENABLE
    /
      ALTER TABLE "SCOTT"."TAB1" RENAME TO "TAB2"
    /
      
    1 row selected.
     
  14. 次のように、DBMS_METADATA_DIFFブラウザAPIを使用して、結果を比較します。

    SQL> SELECT dbms_metadata_diff.compare_alter('TABLE','TAB1','TAB2') FROM dual;
    ALTER TABLE "SCOTT"."TAB1" ADD ("MGR" NUMBER(4,0))
      ALTER TABLE "SCOTT"."TAB1" DROP ("JOB")
      ALTER TABLE "SCOTT"."TAB1" MODIFY ("ENAME" VARCHAR2(20))
      ALTER TABLE "SCOTT"."TAB1" ADD  PRIMARY KEY ("EMPNO") USING INDEX 
      PCTFREE 10 INITRANS 2 STORAGE ( INITIAL 16384 NEXT 16384 MINEXTENTS 1
      MAXEXTENTS 505 PCTINCREASE 50 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL
      DEFAULT)  ENABLE ALTER TABLE "SCOTT"."TAB1" RENAME TO "TAB2"
     
    1 row selected.

26.8 DBMS_METADATA APIのプログラム・インタフェースに関するパフォーマンスのヒント

DBMS_METADATA APIのプログラム・インタフェース使用時にパフォーマンスを向上する方法について説明します。

具体的には次のとおりです。

  1. ある型のすべてのオブジェクトを、次の型のオブジェクトをフェッチする前にフェッチします。たとえば、スキーマ内に含まれるすべてのオブジェクトの定義を取得する場合は、まずすべての表をフェッチし、次にすべての索引をフェッチし、その次にすべてのトリガーをフェッチします。この方法は、OPENコンテキストをネストする方法(表をフェッチした後でそのすべての索引、権限およびトリガーをフェッチし、その後、次の表をフェッチした後でそのすべての索引、権限およびトリガーをフェッチするという方法)より非常に高速です。「DBMS_METADATA APIの使用例」では、この非効率な後者の方法が示されていますが、その例の目的はほとんどのプログラム・コールを示すことであり、この方法がその目的に最適です。

  2. SET_COUNTプロシージャを使用して、複数のオブジェクトを一度に取得します。これによってサーバーのラウンドトリップが最小化され、多くの冗長なファンクション・コールが削減されます。

  3. DBMS_METADATA APIをコールするPL/SQLパッケージを記述する場合、LOB変数およびLOBを含むオブジェクト(SYS.KU$_DDLSなど)は、個々のファンクション内ではなく、パッケージ・スコープで宣言します。これによって、ファンクションの開始および終了時に、負荷の高い操作である、LOBの存続時間構造の作成および削除が実行されなくなります。

26.9 DBMS_METADATA APIの使用例

DBMS_METADATA APIの使用方法の例。

デモを自動的に実行するスクリプトの手順は、次のとおりです。

  • スキーマ(MDDEMO)および何人かの従業員名簿のユーザーを確立します。

  • スキーマ内に従業員名簿に似せた表を3つ作成し、関連する索引、トリガーおよび権限を作成します。

  • DBMS_METADATA APIを使用するPAYROLL_DEMOというパッケージを作成します。PAYROLL_DEMOパッケージには、PAYROLLから始まるMDDEMOスキーマ内の2つの表のDDLを取得するGET_PAYROLL_TABLESというプロシージャを含めます。各表に対して、表の関連する依存オブジェクト、索引、権限およびトリガーのDDLを取得します。すべてのDDLは、MDDEMO.DDLという名前の表に書き込まれます。

例を実行するには、次の手順に従います。

  1. ユーザーsystemとしてSQL*Plusを起動します。パスワードの入力を求められます。

    sqlplus system
    
  2. デモをインストールします。このデモは、rdbms/demoにあるファイルmddemo.sqlに含まれています。

    SQL> @mddemo
    

    このステップで行われる処理の詳細は、「DBMS_METADATAの例で行われる処理」を参照してください。

  3. ユーザーmddemoとして接続します。パスワードを入力するように要求されます。パスワードもmddemoです。

    SQL> CONNECT mddemo
    Enter password:
    
  4. 問合せの出力を完全なものにして読取り可能にするために、次のパラメータを設定します

    SQL> SET PAGESIZE 0
    SQL> SET LONG 1000000
    
  5. 次のとおりGET_PAYROLL_TABLESプロシージャを実行します。

    SQL> CALL payroll_demo.get_payroll_tables();
    
  6. 次のSQL問合せを実行します。

    SQL> SELECT ddl FROM DDL ORDER BY SEQNO;
    

    生成される出力は、GET_PAYROLL_TABLESプロシージャの実行結果です。デモのインストール時に、ステップ2で行われたすべてのDDLが示されます。実際の出力のリストについては、「GET_PAYROLL_TABLESプロシージャで生成される出力」 を参照してください。

26.9.1 DBMS_METADATAの例で行われる処理

DBMS_METADATAの例の説明。

mddemoスクリプトを実行すると、次のステップが行われます。これらのステップをユーザーの状況に合わせることができます。

  1. ユーザーが存在する場合は、次のとおり削除します。これで、新しいデータを使用した作業が開始できます。ユーザーが存在しない場合は、その影響を示すメッセージが表示されますが、問題はありません。デモは継続して実行されます。

    CONNECT system
    Enter password: password
    SQL> DROP USER mddemo CASCADE;
    SQL> DROP USER mddemo_clerk CASCADE;
    SQL> DROP USER mddemo_mgr CASCADE;
    
  2. mddemoで識別されるユーザーmddemoを作成します。

    SQL> CREATE USER mddemo IDENTIFIED BY mddemo;
    SQL> GRANT resource, connect, create session,
      1     create table,
      2     create procedure, 
      3     create sequence,
      4     create trigger,
      5     create view,
      6     create synonym,
      7     alter session,
      8  TO mddemo;
    
  3. clerkで識別されるユーザーmddemo_clerkを作成します。

    CREATE USER mddemo_clerk IDENTIFIED BY clerk;
    
  4. mgrで識別されるユーザーmddemo_mgrを作成します。

    CREATE USER mddemo_mgr IDENTIFIED BY mgr;
    
  5. mddemoとしてSQL*Plusに接続します(パスワードもmddemoです)。

    CONNECT mddemo
    Enter password:
    
  6. いくつかの従業員名簿型の表を作成します。

    SQL> CREATE TABLE payroll_emps
      2  ( lastname VARCHAR2(60) NOT NULL,
      3  firstname VARCHAR2(20) NOT NULL,
      4  mi VARCHAR2(2),
      5  suffix VARCHAR2(10),
      6  dob DATE NOT NULL,
      7  badge_no NUMBER(6) PRIMARY KEY,
      8  exempt VARCHAR(1) NOT NULL,
      9  salary NUMBER (9,2),
      10 hourly_rate NUMBER (7,2) )
      11 /
    
    SQL> CREATE TABLE payroll_timecards 
      2  (badge_no NUMBER(6) REFERENCES payroll_emps (badge_no),
      3  week NUMBER(2),
      4  job_id NUMBER(5),
      5  hours_worked NUMBER(4,2) )
      6 /
    
  7. audit_trailというダミーの表を作成します。この表は、payrollで始まらない表は、GET_PAYROLL_TABLESプロシージャでは取得されないことを示すために使用します。

    SQL> CREATE TABLE audit_trail 
      2  (action_time DATE,
      3  lastname VARCHAR2(60),
      4  action LONG )
      5  /
    
  8. 作成された表の権限を作成します。

    SQL> GRANT UPDATE (salary,hourly_rate) ON payroll_emps TO mddemo_clerk;
    SQL> GRANT ALL ON payroll_emps TO mddemo_mgr WITH GRANT OPTION;
    
    SQL> GRANT INSERT,UPDATE ON payroll_timecards TO mddemo_clerk;
    SQL> GRANT ALL ON payroll_timecards TO mddemo_mgr WITH GRANT OPTION;
    
  9. 作成された表の索引を作成します。

    SQL> CREATE INDEX i_payroll_emps_name ON payroll_emps(lastname);
    SQL> CREATE INDEX i_payroll_emps_dob ON payroll_emps(dob);
    SQL> CREATE INDEX i_payroll_timecards_badge ON payroll_timecards(badge_no);
    
  10. 作成された表のトリガーを作成します。

    SQL> CREATE OR REPLACE PROCEDURE check_sal( salary in number) AS BEGIN
      2  RETURN;
      3  END;
      4  /
    

    例を簡単にするために、セキュリティは比較的低く設定しています。

    SQL> CREATE OR REPLACE TRIGGER salary_trigger BEFORE INSERT OR UPDATE OF salary
    ON payroll_emps
    FOR EACH ROW WHEN (new.salary > 150000)
    CALL check_sal(:new.salary)
    /
    
    SQL> CREATE OR REPLACE TRIGGER hourly_trigger BEFORE UPDATE OF hourly_rate ON payroll_emps
    FOR EACH ROW
    BEGIN :new.hourly_rate:=:old.hourly_rate;END;
    /
    
  11. 生成されたDDLを保持する表を設定します。

    CREATE TABLE ddl (ddl CLOB, seqno NUMBER);
    
  12. DBMS_METADATAプロシージャを使用できる例を提供するPAYROLL_DEMOパッケージを作成します。

    SQL> CREATE OR REPLACE PACKAGE payroll_demo AS PROCEDURE get_payroll_tables;
    END;
    /

    ノート:

    PAYROLL_DEMOパッケージの内容を含めて、この例のスクリプト全体を参照するには、$ORACLE_HOME/rdbms/demoディレクトリにあるファイルmddemo.sqlを参照してください。

26.9.2 GET_PAYROLL_TABLESプロシージャで生成される出力

GET_PAYROLL_TABLESプロシージャから生成される出力の説明。

mddemo.payroll_demo.get_payroll_tables プロシージャの実行後に、次の問合せを実行できます。

SQL> SELECT ddl FROM ddl ORDER BY seqno;

結果は次のとおりです。前述の項で説明したとおり、スクリプトによって実行されたすべてのDDLが反映されます。

CREATE TABLE "MDDEMO"."PAYROLL_EMPS"
   (    "LASTNAME" VARCHAR2(60) NOT NULL ENABLE,
        "FIRSTNAME" VARCHAR2(20) NOT NULL ENABLE,
        "MI" VARCHAR2(2),
        "SUFFIX" VARCHAR2(10),
        "DOB" DATE NOT NULL ENABLE,
        "BADGE_NO" NUMBER(6,0),
        "EXEMPT" VARCHAR2(1) NOT NULL ENABLE,
        "SALARY" NUMBER(9,2),
        "HOURLY_RATE" NUMBER(7,2),
 PRIMARY KEY ("BADGE_NO") ENABLE
   ) ;

  GRANT UPDATE ("SALARY") ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_CLERK";
  GRANT UPDATE ("HOURLY_RATE") ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_CLERK";
  GRANT ALTER ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT DELETE ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT INDEX ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT INSERT ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT SELECT ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT UPDATE ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT REFERENCES ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT ON COMMIT REFRESH ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT QUERY REWRITE ON "MDDEMO"."PAYROLL_EMPS" TO "MDDEMO_MGR" WITH GRANT OPTION;

  CREATE INDEX "MDDEMO"."I_PAYROLL_EMPS_DOB" ON "MDDEMO"."PAYROLL_EMPS" ("DOB")
  PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 10240 NEXT 10240 MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 50
  FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSTEM" ;


  CREATE INDEX "MDDEMO"."I_PAYROLL_EMPS_NAME" ON "MDDEMO"."PAYROLL_EMPS" ("LASTNAME")
  PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 10240 NEXT 10240 MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 50
  FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSTEM" ;

  CREATE OR REPLACE TRIGGER hourly_trigger before update of hourly_rate on payroll_emps
for each row
begin :new.hourly_rate:=:old.hourly_rate;end;
/
ALTER TRIGGER "MDDEMO"."HOURLY_TRIGGER" ENABLE;

  CREATE OR REPLACE TRIGGER salary_trigger before insert or update of salary on payroll_emps
for each row  
WHEN (new.salary > 150000)  CALL check_sal(:new.salary)
/
ALTER TRIGGER "MDDEMO"."SALARY_TRIGGER" ENABLE;


CREATE TABLE "MDDEMO"."PAYROLL_TIMECARDS"
   (    "BADGE_NO" NUMBER(6,0),
        "WEEK" NUMBER(2,0),
        "JOB_ID" NUMBER(5,0),
        "HOURS_WORKED" NUMBER(4,2),
 FOREIGN KEY ("BADGE_NO")
  REFERENCES "MDDEMO"."PAYROLL_EMPS" ("BADGE_NO") ENABLE
   ) ;

  GRANT INSERT ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_CLERK";
  GRANT UPDATE ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_CLERK";
  GRANT ALTER ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT DELETE ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT INDEX ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT INSERT ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT SELECT ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT UPDATE ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT REFERENCES ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT ON COMMIT REFRESH ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;
  GRANT QUERY REWRITE ON "MDDEMO"."PAYROLL_TIMECARDS" TO "MDDEMO_MGR" WITH GRANT OPTION;

  CREATE INDEX "MDDEMO"."I_PAYROLL_TIMECARDS_BADGE" ON "MDDEMO"."PAYROLL_TIMECARDS" ("BADGE_NO")
  PCTFREE 10 INITRANS 2 MAXTRANS 255
  STORAGE(INITIAL 10240 NEXT 10240 MINEXTENTS 1 MAXEXTENTS 121 PCTINCREASE 50
  FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSTEM" ;

26.10 DBMS_METADATAプロシージャの要約

DBMS_METADATA APIによって提供されるプロシージャを簡単に説明します。

これらのプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

次の表では、複数オブジェクトの取得に使用する、DBMS_METADATAプログラム・インタフェースのプロシージャを簡単に説明します。

表26-1 複数オブジェクトの取得に使用するDBMS_METADATAプロシージャ

PL/SQLプロシージャ名 説明
DBMS_METADATA.OPEN()

取得するオブジェクトの型、メタデータのバージョンおよびオブジェクト・モデルを指定します。

DBMS_METADATA.SET_FILTER()

取得するオブジェクトに、オブジェクト名、スキーマなどの制限を指定します。

DBMS_METADATA.SET_COUNT()

1回のFETCH_xxxコールで取得するオブジェクトの最大数を指定します。

DBMS_METADATA.GET_QUERY()

FETCH_xxxで使用される問合せのテキストを返します。これをデバッグの機能として使用できます。

DBMS_METADATA.SET_PARSE_ITEM()

解析して返すオブジェクトの属性を指定して、出力を解析に利用します。DBMS_METADATA_PARSE_ITEMSを問い合せて、すべての有効な解析項目を確認できます。

DBMS_METADATA.ADD_TRANSFORM()

取得したオブジェクトのXML表現に、FETCH_xxxによって適用される変換を指定します。DBMS_METADATA_TRANSFORMSビューを問い合せて、すべての有効なOracle提供の変換を確認できます。

DBMS_METADATA.SET_TRANSFORM_PARAM()

transform_handle.で識別されるXSLTスタイルシートのパラメータを指定しますDBMS_METADATA_TRANSFORM_PARAMSビューを問い合せて、各変換で有効なすべての変換パラメータを確認できます。

DBMS_METADATA.SET_REMAP_PARAM()

transform_handleで識別されるXSLTスタイルシートのパラメータを指定します。

DBMS_METADATA.FETCH_xxx()

OPENSET_FILTERSET_COUNTADD_TRANSFORMなどで確立された基準を満たすオブジェクトのメタデータを返します。

DBMS_METADATA.CLOSE()

OPENによって返されたハンドルを無効にし、関連付けられた状態をクリーンアップします。

次の表では、DBMS_METADATAブラウザ・インタフェースで提供されるプロシージャを簡単に説明します。これらのファンクションは、1つ以上の依存オブジェクトまたは権限付与されたオブジェクトのメタデータを返します。これらのプロシージャでは、異種オブジェクト・タイプを処理できません。

表26-2 ブラウザ・インタフェースで使用するDBMS_METADATAプロシージャ

PL/SQLプロシージャ名 説明
DBMS_METADATA.GET_xxx()

シングル・オブジェクトに対してメタデータを返す方法を提供します。各GET_xxxコールは、OPENプロシージャ、1つか2つのSET_FILTERコール、ADD_TRANSFORMプロシージャ(オプション)、FETCH_xxxコールおよびCLOSEプロシージャで構成されます。

object_typeパラメータには、OPENプロシージャと同じセマンティクスが含まれます。schemaおよびnameはフィルタ処理に使用されます。

変換を指定した場合、セッション・レベルの変換フラグが継承されます。

DBMS_METADATA.GET_DEPENDENT_xxx()

XMLまたはDDLで指定したとおり、1つ以上の依存オブジェクトに対してメタデータが返されます。

DBMS_METADATA.GET_GRANTED_xxx()

XMLまたはDDLで指定したとおり、権限が付与された1つ以上のオブジェクトに対してメタデータが返されます。

次の表では、XMLの送信で使用されるDBMS_METADATAプロシージャおよびファンクションを簡単に説明します。

表26-3 XMLデータの送信に使用するDBMS_METADATAのプロシージャおよびファンクション

PL/SQL名 説明
DBMS_METADATA.OPENW()

書込みコンテキストをオープンします。

DBMS_METADATA.ADD_TRANSFORM()

XML文書の変換を指定します。

DBMS_METADATA.SET_TRANSFORM_PARAM() and 
DBMS_METADATA.SET_REMAP_PARAM()

SET_TRANSFORM_PARAMは、変換のパラメータを指定します。

SET_REMAP_PARAMは、変換の再マップを指定します。

DBMS_METADATA.SET_PARSE_ITEM()

解析するオブジェクト属性を指定します。

DBMS_METADATA.CONVERT()

XML文書をDDLに変換します。

DBMS_METADATA.PUT()

データベースにXML文書を送信します。

DBMS_METADATA.CLOSE()

OPENWでオープンしたコンテキストをクローズします。

26.11 DBMS_METADATA_DIFFプロシージャの要約

DBMS_METADATA_DIFF APIによって提供されるプロシージャおよびファンクションを簡単に説明します。

これらのプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

表26-4 DBMS_METADATA_DIFFのプロシージャおよびファンクション

PL/SQLプロシージャ名 説明

OPENCファンクション

比較するオブジェクトの型を指定します。

ADD_DOCUMENTプロシージャ

比較するSXMLドキュメントを指定します。

FETCH_CLOBファンクションおよびプロシージャ

ADD_DOCUMENTで指定した2つのドキュメント間の差異を示すCLOBを返します。

CLOSEプロシージャ

OPENCによって返されたハンドルを無効にし、関連付けられた状態をクリーンアップします。