ヘッダーをスキップ
Oracle® Databaseアドバンスト・アプリケーション開発者ガイド
11gリリース2 (11.2)
B56259-09
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

19 エディションベースの再定義

エディションベースの再定義を使用すると、アプリケーションの使用中にそのデータベース・コンポーネントをアップグレードでき、停止時間を最小化あるいは排除することができます。

使用中にアプリケーションをアップグレードするには、アプリケーションを構成するデータベース・オブジェクトをコピーし、コピーしたオブジェクトを分離した状態で再定義します。変更内容はアプリケーションのユーザーには影響しません。ユーザーは変更されていないアプリケーションの実行を継続します。変更内容が正しいことを確認したら、アップグレードしたアプリケーションをすべてのユーザーが使用できるようにします。

エディションベースの再定義では、1つ以上のコンポーネント機能を使用します。使用する機能と停止時間は次の要素によって異なります。

データベース・オブジェクトをコピーし、コピーしたデータベース・オブジェクトを分離した状態で再定義するには、常にエディション機能を使用します。この章で説明するオンラインでのアプリケーション・アップグレード手順がエディションベースの再定義と呼ばれるのはこのためです。

再定義するすべてのオブジェクトのオブジェクト・タイプがエディション対応(定義は「エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ」を参照)の場合、使用する機能はエディションのみです。

表はエディション対応タイプではありません。1つ以上の表の構造を変更する場合は、エディショニング・ビュー機能も使用します。

表の構造を変更している間、他のユーザーがその表のデータを変更する必要がある場合は、forward crosseditionトリガーも使用します。アップグレード前のアプリケーションとアップグレード後のアプリケーションが同時に通常使用(ホット・ロールオーバー)されている場合、reverse crosseditionトリガーも使用します。crosseditionトリガーはアプリケーションの永続的な要素ではありません。全ユーザーがアップグレード後のアプリケーションを使用するようになったら削除します。

内容は次のとおりです。

エディション

エディションはスキーマ・オブジェクトではなく、所有者もありません。エディションは1つのネームスペースに作成されます。複数のエディションがデータベースに共存することができます。

データベースには少なくとも1つのエディションが必要です。新規作成またはアップグレードされたOracle Databaseはすべて、ora$baseという名前の1つのエディションから開始されます。

内容は次のとおりです。

エディション・オブジェクトと非エディション・オブジェクト

エディション・オブジェクトは、エディション対応タイプとエディションが有効化された所有者の両方を持つスキーマ・オブジェクトです。(エディション対応タイプは持っているが、エディションが有効化された所有者を持たないスキーマ・オブジェクトは潜在的エディションです。)この場合、そのエディションに対してはこのコピーのみが表示可能です。

非エディション・オブジェクトは、非エディション・タイプのスキーマ・オブジェクトです。エディションは、非エディション・オブジェクトの独自のコピーを持つことはできません。非エディション・オブジェクトは、すべてのエディションで同一です。また、どのエディションでも表示できます。

エディション・オブジェクトは、そのOBJECT_NAMEOWNER、およびEDITION_NAMEにより一意に識別されます。非エディション・オブジェクトは、そのOBJECT_NAMEおよびOWNERにより(EDITION_NAMENULL)一意に識別されます(厳密に言えば、オブジェクトを一意に識別するにはオブジェクトのNAMESPACEも必要ですが、オブジェクトを参照する文では暗黙的または明示的にNAMESPACEが指定されるので、これは無視しても構いません)。

オブジェクトのOBJECT_NAMEOWNER、およびEDITION_NAMEは、静的ディクショナリ・ビュー*_OBJECTSおよび*_OBJECTS_AEに表示できます(表19-1を参照)。

オブジェクトのEDITION_NAMEを知らなくても、このオブジェクトを参照できます(知っていても、指定できません)。参照のコンテキストで、エディションを暗黙的に指定します。コンテキストがデータ定義言語(DDL)文である場合、エディションは、このコマンドを発行したセッションの現行エディションです(現行エディションの詳細は、「現行エディションとセッション・エディション」を参照)。コンテキストがソース・コードである場合、エディションはオブジェクトが実オブジェクトであるものです(「継承オブジェクトと実オブジェクト」を参照)。

内容は次のとおりです。

エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ

次のスキーマ・オブジェクト・タイプはエディション対応です。

  • SYNONYM

  • VIEW

  • すべてのPL/SQLオブジェクト型:

    • FUNCTION

    • LIBRARY

    • PACKAGEおよびPACKAGE BODY

    • PROCEDURE

    • TRIGGER

    • TYPEおよびTYPE BODY

その他のスキーマ・オブジェクト・タイプはすべて非エディション対応です。表は非エディション対応タイプの一例です。

エディション対応タイプのスキーマ・オブジェクトは、その所有者に対してエディションが有効化されている場合はエディション化されます。それ以外の場合は、潜在的エディション・オブジェクトです。

非エディション対応タイプのスキーマ・オブジェクトは、その所有者に対してエディションが有効化されていても、常にエディション化できません。表は非エディション・オブジェクトの一例です。


注意:

この規則には1つ例外があります。SYNONYMはエディション対応タイプですが、パブリック・シノニムは非エディション・オブジェクトです。

エディション・オブジェクトの規則

  • 非エディション・オブジェクトは、エディション・オブジェクトに依存できません。

    次に例を示します。

    • パブリック・シノニムは、エディション・オブジェクトを参照できません。

    • ファンクション索引は、エディション・ファンクションに依存できません。

    • マテリアライズド・ビューは、エディション・ビューに依存できません。

    • 表は、エディションが有効化されているユーザーを所有者とするユーザー定義のデータ型(コレクションまたは抽象データ型(ADT))の列を持つことはできません。

    • 非エディション・サブプログラムは、エディションが有効化されているユーザーを所有者とするサブプログラムを静的に参照することはできません。

    この規則の理由については、「参照されているオブジェクトの実オブジェクト化」を参照してください。

  • ADTをエディション化し、同時に進化させることはできません。

    型進化の詳細は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。

  • エディション・オブジェクトを、FOREIGN KEY制約の始点、または終点にすることはできません。

    この規則が影響するエディション・オブジェクトは、エディション化されたビューのみです。エディション化されたビューとは、通常のビュー、またはエディショニング・ビューのどちらかです。

ユーザーに対するエディションの有効化

ユーザーに対してエディションを有効化するには、CREATE USER、またはALTER USER文のENABLE EDITIONS句を使用します。

静的データ・ディクショナリ・ビューDBA_USERSまたはUSER_USERSEDITIONS_ENABLED列に、エディションが有効化されているユーザーが示されます。

エディションの有効化は遡及的で、これを元に戻すことはできません。ユーザーに対してエディションが有効化されている場合、このユーザーが所有している、または将来所有するエディション対応タイプのオブジェクトはすべて、エディション・オブジェクトです。次のようにして、FORCEを指定しないかぎり、エディション化されていない依存オブジェクトを持ち、潜在的エディション・オブジェクトを所有するユーザーに対してエディションを有効化することはできません。

ALTER USER user_name ENABLE EDITIONS FORCE;

FORCEは、次の状況で便利です。ユーザーABに対してエディションを有効化する必要がある場合。ユーザーAが潜在的エディション・オブジェクトa1a2の所有者である場合。ユーザーBが潜在的エディション・オブジェクトb1b2の所有者である場合。オブジェクトa1がオブジェクトb1に依存している場合。オブジェクトb2がオブジェクトa2に依存している場合。ユーザーABに対してエディションを有効化させるには、次のようにします。

  1. FORCEを使用して、ユーザーAについてエディションを有効化します。

    ALTER USER A ENABLE EDITIONS FORCE;
    

    これで、a1a2はエディション・オブジェクトになり、b2(a2に依存するもの)は無効になりました。

  2. ユーザーBのエディションを有効化します。

    ALTER USER B ENABLE EDITIONS;
    
  3. COMPILEで、適切なALTER文を使用して、b2を再コンパイルします。PL/SQLオブジェクトについては、REUSE SETTINGSも指定してください。

    たとえば、b2がプロシージャの場合、次の文を使用します。

    ALTER PROCEDURE b2 COMPILE REUSE SETTINGS
    

    PL/SQLオブジェクトのためのALTER文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

    SQLオブジェクトのためのALTER文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

FORCEは、次の状況では必要ありません。潜在的エディション・オブジェクトc1を所有しているユーザーCに対してエディションを有効化する必要がある場合。オブジェクトc1が、ユーザーDにより所有されていて、潜在的エディション依存オブジェクトd1を持っている場合。ユーザーDが、所有者がCである依存オブジェクトを持つ、潜在的エディション・オブジェクトを所有していない場合。最初にd1をエディション・オブジェクトにして、Dに対してエディションを有効化した場合、非エディション・オブジェクトはエディション・オブジェクトに依存できないという規則に違反せずに、Cに対してエディションを有効化することができます。

1つ以上の進化したADTを所有するユーザーに対してエディションを有効化することはできません。有効化しようとすると、エラーORA-38820が発生します。ADTが表への依存性を持っていない場合、ALTER TYPE RESET文を使用して、バージョンを1にリセットすることにより、それ以上、表が進化するとみなされないようにすることができます(ADTのバージョンを1にリセットすると、これに依存するものは無効化されます。)


参照:

  • CREATE USERおよびALTER USER文の構文は、『Oracle Database SQL言語リファレンス』を参照してください。

  • 静的データ・ディクショナリ・ビュー*_USERSの詳細は、『Oracle Databaseリファレンス』を参照してください。


エディションの作成

エディションを作成するには、SQL文CREATE EDITIONを使用します。

エディションは既存のエディションの子として作成する必要があります。CREATE EDITION文によって作成される最初のエディションの親はora$baseです。次の文によって、ora$baseの子としてエディションe2が作成されます。

CREATE EDITION e2

(例19-1などでこの文が使用されています。)

Oracle Database 11gリリース2では、エディションの子は最大で1つです。

エディションの子孫は、エディションの子、子の子、その子などを指します。エディションの祖先は、エディションの親、親の親、その親などを指します。ルート・エディションには親はありません。また、リーフ・エディションには子はありません。


参照:

使用するための権限も含む、CREATE EDITION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

継承オブジェクトと実オブジェクト

各データベース・セッションで一度に使用されるエディションは1つのみです。作成時に子エディションは、親エディションで表示可能なデータベースのすべてのエディション・オブジェクトを親エディションから継承します。各継承オブジェクトは子エディションで表示可能です。

継承オブジェクトは、変更時にコピー、すなわち実オブジェクト化されます。つまり、子エディションのユーザーがDDL文(DROP以外)で継承オブジェクトを参照すると、継承オブジェクトはコピーされ、DDL文はコピー(実オブジェクト)のみに作用します。親エディション内の未変更のオブジェクトは、子エディションでは表示可能ではなくなります。


注意:

DDL文CREATE OR REPLACE objectに効果がない場合、objectは実オブジェクト化されません(詳細は、「依存オブジェクトの無効化」を参照)。DDL文ALTER object COMPILEは、常にobjectを実オブジェクト化します。

例19-1は、エディションora$baseでプロシージャhelloを作成してから、ora$baseの子としてエディションe2を作成します。e2helloを起動するときは、継承プロシージャを起動します。このとき、e2helloを変更して、実オブジェクト化します。エディションora$baseのプロシージャhelloは変更されず、e2には表示されなくなります。ここで、e2helloを起動するときは、実プロシージャを起動します。

例19-1 継承オブジェクトと実オブジェクト

  1. 親エディションでプロシージャを作成します。

    CREATE OR REPLACE PROCEDURE hello IS
      BEGIN
        DBMS_OUTPUT.PUT_LINE('Hello, edition 1.');
      END hello;
    /
    
  2. 親エディションでプロシージャを起動します。

    BEGIN hello(); END;
    /
    

    結果:

    Hello, edition 1.
     
    PL/SQL procedure successfully completed.
    
  3. 子エディションを作成します。

    CREATE EDITION e2;
    
  4. 子エディションを使用します。

    ALTER SESSION SET EDITION = e2;
    

    ALTER SESSION SET EDITIONの詳細は、「セッション・エディションの変更」を参照してください。

  5. 子エディションで、次のプロシージャを起動します。

    BEGIN hello(); END;
    /
    

    子エディションは、親エディションからプロシージャを継承します。子エディションにより、継承したプロシージャが起動されます。結果:

    Hello, edition 1.
     
    PL/SQL procedure successfully completed.
    
  6. 子エディションでプロシージャを変更します。

    CREATE OR REPLACE PROCEDURE hello IS
      BEGIN
        DBMS_OUTPUT.PUT_LINE('Hello, edition 2.');
      END hello;
    /
    

    子は、プロシージャの独自のコピーのみ変更します。子のコピーは実オブジェクトです。

  7. プロシージャを起動します。

    BEGIN hello(); END;
    /
    

    子は独自のコピー、実プロシージャを起動します。

    Hello, edition 2.
    
    PL/SQL procedure successfully completed.
    
  8. 親に戻ります。

    ALTER SESSION SET EDITION = ora$base;
    
  9. プロシージャを起動し、これが変更されていないことを確認します。

    BEGIN hello(); END;
    /
    

    結果:

    Hello, edition 1.
     
    PL/SQL procedure successfully completed.
    

内容は次のとおりです。

継承オブジェクトの削除

子エディションのユーザーが継承オブジェクトを削除すると、そのオブジェクトは子エディションでは表示されなくなりますが、親エディションでは引き続き表示可能です。

例19-2は、エディションora$baseでプロシージャgoodbyeを作成してから、ora$baseの子としてエディションe2を作成します。e2goodbyeが削除されると、e2はgoodbyeを起動できなくなりますが、ora$baseでは起動できます(使用するための権限も含む、DROP PROCEDURE文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください)。

例19-2 継承オブジェクトの削除

  1. エディションora$baseでプロシージャを作成します。

    CREATE OR REPLACE PROCEDURE goodbye IS
      BEGIN
        DBMS_OUTPUT.PUT_LINE('Good-bye!');
      END goodbye;
    /
    
  2. プロシージャを起動します。

    BEGIN goodbye; END;
    /
    

    結果:

    Good-bye!
     
    PL/SQL procedure successfully completed.
    
  3. ora$baseの子としてエディションe2を作成します。

    CREATE EDITION e2;
    
  4. エディションe2を使用します。

    ALTER SESSION SET EDITION = e2;
    

    ALTER SESSION SET EDITIONはトップレベルのSQL文である必要があります。詳細は、「セッション・エディションの変更」を参照してください。

  5. e2で、次のプロシージャを起動します。

    BEGIN goodbye; END;
    /
    

    e2により、継承されたプロシージャが起動されます。

    Good-bye!
     
    PL/SQL procedure successfully completed.
    
  6. e2で、次のプロシージャを削除します。

    DROP PROCEDURE goodbye;
    
  7. e2で、削除したプロシージャの起動を試行します。

    BEGIN goodbye; END;
    /
    

    結果:

    BEGIN goodbye; END;
          *
    ERROR at line 1:
    ORA-06550: line 1, column 7:
    PLS-00201: identifier 'GOODBYE' must be declared
    ORA-06550: line 1, column 7:
    PL/SQL: Statement ignored
    
  8. 親に戻ります。

    ALTER SESSION SET EDITION = ora$base;
    
  9. 親で、次のプロシージャを起動します。

    BEGIN goodbye; END;
    /
    

    結果:

    Good-bye!
     
    PL/SQL procedure successfully completed.
    

e2でプロシージャgoodbyeが削除されたため、次のようになります。

  • 子孫では、プロシージャgoodbyeが継承されません。

  • goodbyeというオブジェクトはe2で表示可能でないため、e2では、任意のエディション対応タイプのオブジェクトをgoodbyeという名前を付けて作成できます。e2でこのようなオブジェクトが作成された場合、e2の子孫はこのオブジェクトを継承します。

例19-3では、e2goodbyeという名前のファンクションが作成され、その後、e2の子としてe3という名前のエディションが作成されます。e3プロシージャgoodbye(e2で削除)を起動しようとすると、エラーが発生しますが、e3ファンクションgoodbye(e2で作成)は正常に起動されます。

例19-3 削除済継承オブジェクトの名前を使用したオブジェクトの作成

  1. e2に戻ります。

    ALTER SESSION SET EDITION = e2;
    

    ALTER SESSION SET EDITIONの詳細は、「セッション・エディションの変更」を参照してください。

  2. e2で、goodbyeという名前のファンクションを作成します。

    CREATE OR REPLACE FUNCTION goodbye
      RETURN BOOLEAN
    IS
    BEGIN
      RETURN(TRUE);
    END goodbye;
    /
    
  3. エディションe3を作成します。

    CREATE EDITION e3 AS CHILD OF e2;
    
  4. エディションe3を使用します。

    ALTER SESSION SET EDITION = e3;
    
  5. e3で、プロシージャgoodbyeの起動を試行します。

    BEGIN
      goodbye;
    END;
    /
    

    結果:

      goodbye;
      *
    ERROR at line 2:
    ORA-06550: line 2, column 3:
    PLS-00221: 'GOODBYE' is not a procedure or is undefined
    ORA-06550: line 2, column 3:
    PL/SQL: Statement ignored
    
  6. e3で、ファンクションgoodbyeを起動します。

    BEGIN
      IF goodbye THEN
        DBMS_OUTPUT.PUT_LINE('Good-bye!');
      END IF;
    END;
    /
    

    結果:

    Good-bye!
     
    PL/SQL procedure successfully completed.
    

参照されているオブジェクトの実オブジェクト化

あるエディションで参照オブジェクトが実オブジェクト化されると、そのエディションにあるそのオブジェクトのすべての直接依存オブジェクトと間接依存オブジェクトが実オブジェクト化されて無効な状態になります。したがって、エディション・オブジェクトは、実オブジェクト化できない依存オブジェクトを持つことはできません。言い換えれば、非エディション・オブジェクトは、エディション・オブジェクトに依存できません(例については、「エディション・オブジェクトの規則」を参照)。

無効なオブジェクトが参照されている場合、データベースは自動的にこれを検証しますが、そのためには名前解決が必要です。データベースはまず、現行エディションでこのオブジェクト名を探し、次に親エディションの検索に進みます。


参照:

無効化、再有効化、名前解決を含む、スキーマ・オブジェクト間の依存性の詳細は、第18章「スキーマ・オブジェクトの依存性」を参照してください。

一部のユーザーに対してエディションを使用可能にする

エディションの作成者には、エディションに対するUSE権限WITH GRANT OPTIONが自動的に付与されます。他のユーザーにエディションのUSE権限を付与するには、SQL文GRANT USE ON EDITIONを使用します。GRANT文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

すべてのユーザーに対してエディションを使用可能にする

すべてのユーザーがエディションを使用できるようにするには、次のいずれかの手順を実行します。

  • エディションのUSE権限をPUBLICに付与します。

    GRANT USE ON EDITION edition_name TO PUBLIC
    

    GRANT文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

  • このエディションを、データベースのデフォルト・エディションにします。

    ALTER DATABASE DEFAULT EDITION = edition_name
    

    これには、edition_nameUSE特権がPUBLICに付与されるという副作用もあります。

    ALTER DATABASE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

現行エディションとセッション・エディション

各データベース・セッションで一度に使用されるエディションは1つのみです。データベース・セッションがある時点で使用するエディションは、現行エディションと呼ばれます。データベース・セッションが開始すると、現行エディションがセッション・エディションになります。これは、データベース・セッションが開始するときのエディションです。セッション・エディションを変更すると、現行エディションも同様に変更されます。ただし、現行エディションとセッション・エディションが異なる状況もあります。

内容は次のとおりです。

最初のセッション・エディション

データベースに接続するときに、最初のセッション・エディションを指定できます。USE権限を持っている任意のエディションを最初のセッション・エディションにすることができます。使用できるエディションの名前を表示するには、次の問合せを使用します。

SELECT EDITION_NAME FROM ALL_EDITIONS;

接続時に最初のセッション・エディションをどのように指定するかは、データベースの接続方法によって異なります。インタフェースのドキュメントを参照してください。


参照:

  • デフォルト・エディションの設定の詳細は、『Oracle Database管理者ガイド』を参照してください。

  • SQL*Plusを使用するデータベースへの接続の詳細は、『SQL*Plusユーザーズ・ガイドおよびリファレンス』を参照してください。

  • Oracle Call Interface(OCI)を使用するデータベースへの接続の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

  • JDBCを使用するデータベースへの接続の詳細は、『Oracle Database JDBC開発者ガイド』を参照してください。


Oracle Database 11gリリース2 (11.2.0.2)では、接続時にセッション・エディションを指定しない場合、次のようになります。

  • データベース・サービスを使用してデータベースに接続し、そのサービスで最初のセッション・エディションが指定された場合、そのサービスの最初のセッション・エディションが最初のセッション・エディションになります。

  • そうでない場合、データベースのデフォルト・エディションが最初のセッション・エディションになります。

リリース11.2.0.2では、データベース・サービスの作成または変更時に、その最初のセッション・エディションを指定できます。

データベース・サービスを作成または変更にするには、srvctl add serviceまたはsrvctl modify serviceコマンドを使用することをお薦めします。サービスのデフォルトの最初のセッション・エディションを指定するには、-tオプションを使用します。

また、DBMS_SERVICE.CREATE_SERVICEまたはDBMS_SERVICE.MODIFY_SERVICEプロシージャを使用してデータベース・サービスを作成または変更して、EDITION属性を使用してデフォルトの最初のセッション・エディションを指定できます。


注意:

Oracle Database 11gリリース2では、DBMS_SERVICE.CREATE_SERVICEおよびDBMS_SERVICE.MODIFY_SERVICEプロシージャは、Oracle ClusterwareおよびOracle Restartにより管理されるデータベースで非推奨です。


参照:

  • srvctl add serviceコマンドの-tオプションの詳細は、『Oracle Database管理者ガイド』を参照してください。

  • srvctl modify serviceコマンドの-tオプションの詳細は、『Oracle Database 管理者ガイド』を参照してください。

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

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


セッション・エディションの変更

データベースに接続した後で、SQL文ALTER SESSION SET EDITIONを使用してセッション・エディションを変更することができます。セッション・エディションは、USE権限のある任意のエディションに変更することができます。セッション・エディションを変更すると、現行エディションも同じセッション・エディションに変更されます。

例19-1および例19-2に含まれる次の文は、まずセッション・エディション(現行エディション)をe2に変更し、その後ora$baseに変更します。

ALTER SESSION SET EDITION = e2
...
ALTER SESSION SET EDITION = ora$base

注意:

ALTER SESSION SET EDITIONはトップレベルのSQL文である必要があります。たとえば、ログオン・トリガーでエディションの変更を遅らせるには、DBMS_SESSION.SET_EDITION_DEFERREDプロシージャを使用します。


参照:

  • ALTER SESSION SET EDITION文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

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


現行エディション名とセッション・エディション名の表示

次の文によって、現行エディションの名前が返されます。

SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') FROM DUAL;

次の文によって、セッション・エディションの名前が返されます。

SELECT SYS_CONTEXT('USERENV', 'SESSION_EDITION_NAME') FROM DUAL;

参照:

SYS_CONTEXT関数の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

現行エディションがセッション・エディションと異なる状況

次のような場合に、現行エディションがセッション・エディションと異なることがあります。

  • crosseditionトリガーが起動される場合。

    詳細は、「crosseditionトリガーとエディションの相互作用」を参照してください。

  • 例19-4のように、DBMS_SQL.PARSEプロシージャをコールして、文を実行するエディションを指定することで、文を実行する場合。

    文が実行している間、指定されたエディションが現行エディションになりますが、セッション・エディションは変更されません。DBMS_SQL.PARSEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

例19-4では、セッション・エディションと現行エディションの名前を返すファンクションが作成されます。その後、子エディションが作成され、子エディションによってそのファンクションが2回起動されます。1回目はセッション・エディションと現行エディションは同じです。2回目は異なります。別のエディションがパラメータとしてDBMS_SQL.PARSEプロシージャに渡されるためです。

例19-4 セッション・エディションと異なる現行エディション

  1. セッション・エディションと現行エディションの名前を返すファンクションを作成します。

    CREATE OR REPLACE FUNCTION session_and_current_editions
      RETURN VARCHAR2
    IS
    BEGIN
      RETURN
      'Session: '|| SYS_CONTEXT('USERENV', 'SESSION_EDITION_NAME') ||
      ' / ' ||
      'Current: '|| SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME');
    END session_and_current_editions;
    /
    
  2. 子エディションを作成します。

    CREATE EDITION e2 AS CHILD OF ora$base;
    
  3. 子エディションを使用します。

    ALTER SESSION SET EDITION = e2;
    
  4. ファンクションを起動します。

    BEGIN
      DBMS_OUTPUT.PUT_LINE (session_and_current_editions());
    END;
    /
    

    結果:

    Session: E2 / Current: E2
     
    PL/SQL procedure successfully completed.
    
  5. ファンクションをもう一度起動します。

    DECLARE
      c     NUMBER := DBMS_SQL.OPEN_CURSOR();
      v     VARCHAR2(200);
      dummy NUMBER;
      stmt  CONSTANT VARCHAR2(32767)
        := 'SELECT session_and_current_editions() FROM DUAL';
    BEGIN
      DBMS_SQL.PARSE (c => c,
                      statement => stmt,
                      language_flag => DBMS_SQL.NATIVE,
                      edition => 'ora$base');
     
      DBMS_SQL.DEFINE_COLUMN (c, 1, v, 200);
      dummy := DBMS_SQL.EXECUTE_AND_FETCH (c, true);
      DBMS_SQL.COLUMN_VALUE (c, 1, v);
      DBMS_SQL.CLOSE_CURSOR(c);
      DBMS_OUTPUT.PUT_LINE (v);
    END;
    /
    

    結果:

    Session: E2 / Current: ORA$BASE
     
    PL/SQL procedure successfully completed.
    

エディションのリタイア

新しいエディション(アップグレードしたアプリケーション)をすべてのユーザーが使用できるようにしたら、SYS以外のユーザーがリタイアしたエディションを使用できないようにするために、古いエディション(元のアプリケーション)をリタイアさせます。


注意:

古いエディションがデータベースのデフォルト・エディションである場合は、この古いエディションをリタイアさせる前に、別のエディションをデフォルトにします。
ALTER DATABASE DEFAULT EDITION = edition_name

ALTER DATABASE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。


エディションをリタイアさせるには、このエディションに対するUSE権限を、すべての権限受領者から取り消します。権限受領者のリストを表示するには、次の問合せを使用します。ここで、eには削除するエディションの名前が入ります。

SELECT GRANTEE, PRIVILEGE
FROM DBA_TAB_PRIVS
WHERE TABLE_NAME = :e
/

REVOKE文の詳細は『Oracle Database SQL言語リファレンス』を参照してください。

エディションの削除


注意:

エディションにcrosseditionトリガーが含まれている場合は、エディションを削除する前に、「crosseditionトリガーの削除」を参照してください。

エディションを削除するには、DROP EDITION文を使用します。詳細は、『Oracle Database SQL言語リファレンス』を参照してください。エディションに実オブジェクトがある場合は、実オブジェクトを削除するCASCADE句を指定する必要があります。

DROP EDITION edition CASCADE文が正常終了前に(たとえば、停電などの理由で)中断された場合、静的データ・ディクショナリ・ビュー*_EDITIONSには、editionに対するUSABLEの値がNOであることが表示されます。このように使用できないeditionに対して実行できる唯一の操作は、DROP EDITION CASCADEです。

エディションは次の場合に削除します。

  • アプリケーション・アップグレードをロールバックする必要がある場合。

  • (オプション)エディションをリタイアさせた場合。

エディションを削除できるのは、次のすべての条件に該当する場合のみです。

  • エディションがルート・エディション、またはリーフ・エディションである場合。

  • エディションがルートの場合、その子孫により継承されているオブジェクトを持っていない場合。(つまり、ルート・エディションから継承された各オブジェクトは、実オブジェクト化されたか、削除された場合)。

  • エディションが使用されていない場合(つまり、セッションの現行エディションまたはセッション・エディションではない場合)。

  • このエディションが、データベースのデフォルト・エディションではない場合。

子エディションで継承オブジェクトを明示的に実オブジェクト化するには、次のようにします。

  1. 子エディションをセッション・エディションにします。

    手順は、「セッション・エディションの変更」を参照してください。

  2. COMPILEで、適切なALTER文を使用して、このオブジェクトを再コンパイルします。PL/SQLオブジェクトについては、REUSE SETTINGSも指定してください。

    たとえば、次の文ではプロシージャp1が実オブジェクト化されます。

    ALTER PROCEDURE p1 COMPILE REUSE SETTINGS
    

    PL/SQLオブジェクトのためのALTER文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

    SQLオブジェクトのためのALTER文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。


参照:

  • ALTER LIBRARY文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

  • ALTER VIEW文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

  • ALTER FUNCTION文の詳細は、Oracle Database PL/SQLリファレンスを参照

  • ALTER PACKAGE文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

  • ALTER PROCEDURE文の詳細は、Oracle Database PL/SQL言語リファレンスを参照

  • ALTER TRIGGER文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

  • ALTER TYPE文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。


エディショニング・ビュー

エディショニング・ビューを作成する前に、エディショニング・ビューの所有者に対してエディションを有効化しておく必要があります。

エディショニング・ビュー以外のビューで定義できるトリガーのタイプは、INSTEAD OFトリガーのみです。エディショニング・ビューでは、表で定義できるトリガー・タイプすべてを定義できます(ただし、crosseditionトリガー(一時トリガー)とINSTEAD OF トリガーは例外です)。このため、またエディショニング・ビューはエディション化が可能であることによって、エディショニング・ビューを使用することで、実表がエディション化されたかのように扱うことができます。ただし、アップグレードされたアプリケーションにより、新しい索引または制約が必要とされる場合、エディショニング・ビューに索引または制約を追加することはできません。これらは実表に追加する必要があります。

エディショニング・ビューは1つの実表の列のサブセットを選択し、オプションとしてそれらの列に別名を提供します。別名を提供するとき、エディショニング・ビューは物理列名(実表で使用される)を論理列名(アプリケーションで使用される)にマップします。エディショニング・ビューは、表のAPIに似ています。

直接ではなく、エディショニング・ビュー経由で表にアクセスすることに対するパフォーマンス・ペナルティはありません。つまり、SQL SELECTINSERTUPDATEDELETE、またはMERGE文で1つ以上のエディショニング・ビューが1回以上使用されているときに、必要に応じて、エディショニング・ビューの名前を実表の名前で置き換え、列名を調整した場合でも、パフォーマンスは変わりません。

静的データ・ディクショナリ・ビュー*_EDITIONING_VIEWSは、セッション・エディションで表示可能なデータベース内のすべてのエディショニング・ビュー(実エディショニング・ビューまたは継承エディショニング・ビュー)を示します。*_EDITIONING_VIEWS_AEは、すべてのエディションにおけるデータベース内のすべてのエディショニング・ビューのすべての実オブジェクトを示します。

内容は次のとおりです。


参照:

静的データ・ディクショナリ・ビュー*_EDITIONING_VIEWSおよび*_EDITIONING_VIEWS_AEの詳細は、『Oracle Databaseリファレンス』を参照してください。

エディショニング・ビューの作成

エディショニング・ビューを作成するには、SQL文CREATE VIEWをキーワードEDITIONINGとともに使用します。エディショニング・ビューを読取り専用にするには、WITH READ ONLYを指定します。読取り/書込みにするにはWITH READ ONLYを省略します。

エディショニング・ビューが読取り専用の場合、未変更アプリケーションのユーザーが実表のデータを見ることはできますが、変更することはできません。この実表は準可用性を備えています。準可用性を利用できるのは、ユーザーが読むだけで変更しない、オンライン・ディクショナリなどのアプリケーションです。実表にcrosseditionトリガーを定義しない場合は、エディショニング・ビューを読取り専用にします。

エディショニング・ビューが読取り/書込みの場合、未変更アプリケーションのユーザーが、実表のデータを見ることも変更することもできます。この実表は最大可用性を備えています。最大可用性が必要となるのは、ユーザーが注文を発行するオンライン・ストアなどのアプリケーションです。実表にcrosseditionトリガーを定義する場合は、エディショニング・ビューを読取り/書込みにします。

エディショニング・ビューは、実表からの列のサブセットの選択と列の別名提供の他にも機能を実行する必要があるため、エディショニング・ビューを作成するCREATE VIEW文には制限があります。制限に違反すると、FORCEを指定していてもビューの作成が失敗します。


参照:

制限を含む、CREATE VIEW文を使用したエディショニング・ビューの作成の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

パーティション拡張エディショニング・ビュー名

パーティション表に定義されているエディショニング・ビューには、パーティション拡張名を付けることができます。この名前は、実表のパーティションおよびサブパーティションを示すパーティション名とサブパーティション名を含みます。

パーティション拡張表名に対応するデータ操作言語(DML)は、パーティション拡張エディショニング・ビュー名にも対応します。次の文が対応しています。

  • DELETE

  • INSERT

  • SELECT

  • UPDATE


参照:

パーティション表の参照の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディショニング・ビューの書込み可能性の変更

既存のエディショニング・ビューを読取り専用から読取り/書込みに変更するには、SQL文ALTER VIEW READ WRITEを使用します。既存のエディショニング・ビューを読取り/書込みから読取り専用に変更するには、SQL文ALTER VIEW READ ONLYを使用します。


参照:

ALTER VIEW文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディショニング・ビューの置換

エディショニング・ビューを置換するには、SQL文CREATE VIEWOR REPLACE句およびキーワードEDITIONINGとともに使用します。

エディショニング・ビューを置換できるのは別のエディショニング・ビューのみです。置換対象のエディショニング・ビューに定義されているトリガーはすべて保持されます。

実表の削除または名前変更

エディショニング・ビューの定義が基づいている実表を削除したり名前を変更したりしても、エディショニング・ビューは削除されませんが、エディショニング・ビューとその依存オブジェクトが無効になります。ただし、エディショニング・ビューに定義されているトリガーはすべて保持されます。

実表への索引と制約の追加

アップグレードされたアプリケーションにより、新しい索引または制約が必要とされる場合は、これらを実表に追加する必要があります。これらをエディショニング・ビューに追加することはできません。

新しい索引が古いエディション(元のアプリケーション)に悪い影響を与える場合は、これらを非表示にします。新しい索引の使用が必要なcrosseditionトリガーで、これらをINDEXヒントに指定します。

すべてのユーザーがアップグレードされたアプリケーションのみを使用している場合は、次のようにします。

  • 新しい索引を使用しているのがcrosseditionトリガーのみである場合は、これらの索引を削除します。

  • アップグレードされたアプリケーションが新しい索引で便利である場合は、これらを表示します。


参照:


SQLオプティマイザ索引ヒント

SQLオプティマイザ索引ヒントは、索引を構成する列の論理名を使用して指定されます。論理列名を使用してエディショニング・ビューに指定されたSQLオプティマイザ索引ヒントは、実表の対応する物理列の索引にマップする必要があります。


参照:

ヒントの使用方法の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

crosseditionトリガー

crosseditionトリガーと非crosseditionトリガーの最も大きな違いは、エディションとの相互作用の方法です。crosseditionトリガーは、それが実であるエディションにのみ表示されます。子孫エディションでは表示されません。forward crosseditionトリガーは、データを古いエディションが使用していた列から、新しいエディションが使用している列に移動します。reverse crosseditionトリガーは逆方向へデータを移動します。

この他の重要な違いは次のとおりです。

  • crosseditionトリガーは、他の表に定義されたトリガーに対して並べ替えることができますが、非crosseditionトリガーは同じ表に定義されたトリガーに対してのみ並べ替えることができます。

  • crosseditionトリガーは一時的に使用します。構成を変更した表をすべてのユーザーが使用できるようにした後で削除します。

内容は次のとおりです。


参照:

トリガーの詳細は、Oracle Database PL/SQL言語リファレンスを参照

forward crosseditionトリガー

アップグレード後のエディションでDML変更を表に行うと、新しい列または新しい表のみに書き込まれ、アップグレード前(祖先)エディションのユーザーが読取りまたは書込みを行う可能性がある列に対しては行われません。ただし、祖先エディションのユーザーが表データを変更する場合、表示しているエディショニング・ビューがそれらの変更内容を正確に反映する必要があります。これは、forward crosseditionトリガーを使用することで実現します。

forward crosseditionトリガーはトランスフォームを定義します。これは、古い行を1つ以上の新しい行に変換するための規則です。古い行は、アップグレード前の表現に含まれるデータ行です。新しい行は、アップグレード後の表現に含まれるデータ行です。トリガーの名前はトリガー自体、およびこのトリガーにより定義された変換を表します。

reverse crosseditionトリガー

アップグレード前のエディションとアップグレード後のエディションが同時に通常使用(ホット・ロールオーバー)されている場合、reverse crosseditionトリガーを使用して、アップグレード後エディションのユーザーが表データを変更するときに、変更内容がアップグレード前エディションに正確に反映されるようにします。

crosseditionトリガーとエディションの相互作用

crosseditionトリガーと非crosseditionトリガーの最も大きな違いは、エディションとの相互作用の方法です。

ここでは、現行エディションは、トリガーを起動するDML文が実行されるエディションを指します。現行エディションはセッション・エディションと異なることがあります(詳細は、「現行エディションがセッション・エディションと異なる状況」を参照)。

表示可能なトリガー

エディションは、非crosseditionトリガーを他のエディション・オブジェクトと同じように継承します(「継承オブジェクトと実オブジェクト」を参照)。

エディションはcrosseditionトリガーは継承しません。crosseditionトリガーは、別のエディションで実行されるDML文に対応して起動されることもありますが、名前が表示されるのは作成されたエディションのみです。したがって、エディションでは、祖先エディションで作成されたcrosseditionトリガーの名前を再利用できます。crosseditionトリガーの名前を再利用しても、古いトリガーの起動条件は変更されません。

静的データ・ディクショナリ・ビューに示されるcrosseditionトリガーは、現行エディションの実オブジェクトです。

起動できるトリガーの種類

起動できるトリガーの種類は、トリガーするDML文のカテゴリによって異なります。このカテゴリは次のとおりです。


注意:

SQL INSERT文にAPPENDヒントを指定してもcrosseditionトリガーの起動を防ぐことはできません。APPENDヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

forward crosseditionトリガーSQL

forward crosseditionトリガーSQLは、次のいずれかの方法で実行されるSQLです。

  • forward crosseditionトリガー本体から直接起動

    forward croseditionトリガーのローカル・サブプログラムが起動された場合のみ、このカテゴリには、起動されたサブプログラムのSQLが含まれます。

  • apply_crossedition_triggerパラメータに対してNULL以外の値を指定してDBMS_SQL.PARSEプロシージャを起動

    apply_crossedition_triggerパラメータに対して唯一有効なNULL以外の値は、forward crosseditionトリガーの非修飾名です。DBMS_SQL.PARSEプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

forward crosseditionトリガーが別のコンパイル・ユニットに含まれるサブプログラムを起動する場合、このトリガーがapply_crossedition_triggerパラメータにNULL以外の値が指定されたDBMS_SQL.PARSEプロシージャにより起動された場合のみ、このサブプログラムのSQLがforward crosseditionトリガーSQLになります。

forward crosseditionトリガーSQLは、次の条件をすべて満たすトリガーのみ起動できます。

  • forward crosseditionトリガーである。

  • 現行エディションまたは現行エディションの子孫で作成された。

  • 実行中のforward crosseditionトリガーに明示的に後続する。

reverse crosseditionトリガーSQL

reverse crosseditionトリガーSQLは、reverse crosseditionトリガー本体から直接実行されるSQLです。reverse croseditionトリガーのローカル・サブプログラムが起動された場合のみ、このカテゴリには、起動されたサブプログラムのSQLが含まれます。

reverse crosseditionトリガーSQLは、次の条件をすべて満たすトリガーのみ起動できます。

  • reverse crosseditionトリガーである。

  • 現行エディションまたは現行エディションの先祖で作成された。

  • 実行中のreverse crosseditionトリガーよりも前に明示的に実行される。

アプリケーションSQL

アプリケーションSQLは、crosseditionトリガーSQLを除くすべてのSQLで、次のDML文が含まれます。

  • DBMS_SQLパッケージを使用してコーディングされた動的SQL DML文(これらの文の詳細は『Oracle Database PL/SQL言語リファレンス』を参照)。

  • Javaストアド・プロシージャおよび外部プロシージャによって実行されるDML文(これらのプロシージャがCALLトリガーで起動された場合も含む)

アプリケーションSQLは、次の規則に従って、noncrosseditionトリガーとcrosseditionトリガーの両方を起動します。

トリガーの種類 トリガーの起動条件
noncrossedition トリガーが現行エディションで表示可能かつ有効である。
forward crossedition トリガーが現行エディションの子孫で作成された。
reverse crossedition トリガーが現行エディションまたは現行エディションの祖先で作成された。

起動順序

特定のDML文に対応してトリガーを起動するためのトリガーの条件は次のとおりです。

これらの条件を満たすトリガーの場合、起動順序は次により決定されます。


参照:

トリガーの起動順序に関する概要は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

FOLLOWS句およびPRECEDES句

トリガーAとBが同じタイミング・ポイントで起動されるとき、次のいずれかに該当するとAはBよりも先に起動します。

  • Aが明示的にBに先行する場合。

  • Bが明示的にAに続く場合。

この規則は次のような条件とは無関係です。

  • トリガーが有効か無効か。

  • UPDATE OF句に指定された列が変更されるかどうか。

  • WHEN句が満たされるかどうか。

  • 2つのトリガーが同じ種類のDML文(INSERTUPDATEまたはDELETE)に関連付けられているかどうか。

  • トリガーのタイミング・ポイントが重なっているかどうか。

明示的な先行または後続の関係がないトリガーの起動順序は予測できません。

トリガーの種類とエディション

トリガーを起動するDML文に関連付けられた各タイミング・ポイントでは、条件に合うトリガーが次の順序で起動されます。1から3ではFOLLOWSの関係が適用され、45ではPRECEDESの関係が適用されます。

  1. 非crosseditionトリガー

  2. 現行エディションで作成されたforward crosseditionトリガー

  3. 現行エディションの子孫で作成されたforward crosseditionトリガー(子孫の作成順(子、孫、その子など))

  4. 現行エディションで作成されたreverse crosseditionトリガー

  5. 現行エディションの祖先で作成されたreverse crosseditionトリガー(祖先の作成と逆順(親、その親、さらにその親など))

crosseditionトリガーの実行

crosseditionトリガーは、自らが作成されたエディションを使用して実行します。crosseditionトリガーがコールするすべてのコード(パッケージ参照、PL/SQLサブプログラム・コールおよびSQL文を含む)も、crosseditionトリガーが作成されたエディションで実行します。

PL/SQLパッケージが複数のエディションで実パッケージである場合、単一セッション内であっても、パッケージの変数やその他の状態は各エディションのみで公開されます。各crosseditionトリガーおよびそれらのトリガーがコールするコードは、crosseditionトリガーが作成されたエディションを使用して実行するため、同一セッションがパッケージの複数のバージョンを同じ名前でインスタンス化することがあります。

crosseditionトリガーの作成

crosseditionトリガーを作成するには、エディションが有効化されたユーザーである必要があります(ユーザーに対してエディションを有効にする方法の詳細は「ユーザーに対するエディションの有効化」を参照)。

次の規則に注意しながらSQL文CREATE TRIGGERを使用して、crosseditionトリガーを作成します。

  • crosseditionトリガーは、ビューではなく表に定義する必要があります。

  • crosseditionトリガーはDMLトリガー(単純トリガーまたは複合トリガー)であることが必要です。

    crosseditionトリガー本体のDML文は、静的SQL文(『Oracle Database PL/SQL言語リファレンス』を参照)、またはネイティブ動的SQL文(『Oracle Database PL/SQL言語リファレンス』を参照)のどちらかです。

  • crosseditionトリガーは、REVERSEを指定しないかぎりforwardになります。(FORWARDの指定はオプションです。)

  • FOLLOWS句を使用できるのは、forward crosseditionトリガーまたは非crosseditionトリガーを作成する場合のみです。(FOLLOWS句は、作成中のトリガーが、指定したトリガーの起動後に起動することを指定します。)

  • PRECEDES句を使用できるのは、reverse crosseditionトリガーを作成する場合のみです。(PRECEDES句は、作成中のトリガーが、指定したトリガーの起動前に起動することを指定します。)

  • FOLLOWS句またはPRECEDES句に指定するトリガーは存在している必要がありますが、有効になっていなくても、正常にコンパイルされていなくてもかまいません。

  • 非crosseditionトリガーと同じく、crosseditionトリガーは、DISABLEを指定しないかぎり作成された時点で有効になっています。(ENABLEの指定はオプションです。)


    ヒント:

    crosseditionトリガーは無効な状態で作成して、正常にコンパイルされたことを確認した後で有効にします。有効な状態で作成してからコンパイルが失敗すると、既存のアプリケーションのユーザーの操作が影響を受けます。

  • crosseditionトリガー本体の操作は多重呼出し不変(操作を複数回実行するのは冗長であり、結果は変わらない)である必要があります。


参照:

crosseditionトリガーを作成するCREATE TRIGGER文の使用方法の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

forward crosseditionトリガー本体のコーディング

forward crosseditionトリガーの本体の操作は、予測が不可能であるため、多重呼出し不変である必要があります。

  • 古い行に対して本体が最初に実行されるコンテキスト。

    可能性は次のとおりです。

  • 本体が古い行それぞれについて何回実行されるか。

内容は次のとおりです。

データ変換における衝突の処理

forward crosseditionトリガーが(表の新しい列ではなく)新しい表を移入する場合、その本体は必ずデータ変換の衝突に対応します。

たとえば、新しい表のある列にUNIQUE制約が含まれるとします。予期せぬ変更によりforward crosseditionトリガーが起動され、これにより新しい表に1行挿入されます。その後、別の予期せぬ変更により、forward crosseditionトリガーが起動されるか、またはユーザーがトリガーにより定義された変換を適用します。このトリガーは新しい表への行の挿入を試行しますが、これはUNIQUE制約に違反しています。

衝突処理方法がトリガーの実行理由に応じて変わる場合、その理由はファンクションAPPLYING_CROSSEDITION_TRIGGERにより判断できます。このファンクションがトリガーの本体から直接呼び出されたときに、予期せぬ変更によりトリガーが実行されていた場合はBOOLEAN値のTRUEが返されます。また、変換が適用されたためにトリガーが実行されていた場合はFALSEが返されます。(APPLYING_CROSSEDITION_TRIGGERは、パッケージDBMS_STANDARDで定義されています。これにはパラメータはありません。)これにはパラメータはありません。)

衝突を無視し、既存の行と衝突しない行を挿入するには、INSERT文にIGNORE_ROW_ON_DUPKEY_INDEXヒントを入れます。

このような衝突を無視したくはないが、これらに対応するために、衝突がどこで発生しているかを知る必要があるという場合は、INSERTまたはUPDATE文にCHANGE_DUPKEY_ERROR_INDEXヒントを入れ、索引または列のセットを指定します。その後、索引、または列のセットに一意キーの違反が発生した場合、ORA-00001のかわりにORA-38911が報告されます。ORA-38911に対する例外ハンドラを書くことができます。


注意:

ヒントの構文もありますが、IGNORE_ROW_ON_DUPKEY_INDEXおよびCHANGE_DUPKEY_ERROR_INDEXは必須です。これらはオプティマイザにより必ず使用されます。

例19-5APPLYING_CROSSEDITION_TRIGGERファンクション、およびIGNORE_ROW_ON_DUPKEY_INDEXヒントとCHANGE_DUPKEY_ERROR_INDEXヒントを使用して、データ変換の衝突に対応するcrosseditionトリガーを作成します。このトリガーはtable1の古い行をtable2の新しい行に変換します。この表を次のように作成されます。

CREATE TABLE table1 (key NUMBER, value VARCHAR2(20));

CREATE TABLE table2 (key NUMBER, value VARCHAR2(20), last_updated TIMESTAMP);
CREATE UNIQUE INDEX i2 on table2(key);

例19-5 データ変換の衝突に対応するcrosseditionトリガー

CREATE OR REPLACE TRIGGER trigger1
  BEFORE INSERT OR UPDATE ON table1
  FOR EACH ROW
  CROSSEDITION
DECLARE
  row_already_present  EXCEPTION;
  PRAGMA EXCEPTION_INIT(row_already_present, -38911);
BEGIN
  IF APPLYING_CROSSEDITION_TRIGGER THEN
    /* Trigger is running because of serendipitous change.
       Insert new row into table2 unless it is already there. */
    INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(table2(key)) */
    INTO table2
    VALUES(:new.key, :new.value, to_date('1900-01-01', 'YYYY-MM-DD'));
  ELSE
    /* Trigger is running because you are applying transform.
       If tranform has not yet inserted new row in table2, insert new row;
       otherwise, update new row. */
    BEGIN
      INSERT /*+ CHANGE_DUPKEY_ERROR_INDEX(table2(key)) */
      INTO table2
      VALUES(:new.key, :new.value, SYSTIMESTAMP);
    EXCEPTION WHEN row_already_present THEN
      UPDATE table2
      SET value = :new.value, last_updated = SYSTIMESTAMP
      WHERE key = :new.key;
    END;
  END IF;
END;
/

参照:

  • IGNORE_ROW_ON_DUPKEY_INDEXの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

  • CHANGE_DUPKEY_ERROR_INDEXの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

  • ヒントの概要は、『Oracle Database SQL言語リファレンス』を参照してください。


他の表への変更の処理

トリガーが定義された表以外の表を変更する明示的なSQL文がforward croseditionトリガーの本体に含まれ、それらの表の行にトリガーが定義された表の行との1対1の対応がない場合、次の状況を正しく処理するためのロック・メカニズムを本体コードに実装する必要があります。

  • 祖先エディションの複数のユーザーが、トリガーの定義されている表に対するDML文を同時に発行する状況。

  • 祖先エディションのユーザーのうち、少なくとも1人が、トリガーの定義されている表に対するDML文を発行する状況。

アップグレード前の表現をアップグレード後の表現に変換

アップグレードしているアプリケーションを構成するデータベース・オブジェクトを(新しいエディションで)再定義した後、アプリケーション・データを(古いエディションで)アップグレード前の表現から(新しいエディションで)アップグレード後の表現に変換する必要があります。この変換の規則はトランスフォームと呼ばれ、これらはforward crosseditionトリガーにより定義されます。(forward crosseditionトリガーについては、「forward crosseditionトリガー」を参照してください。)

古い行の一部は、予期せぬ変更、つまり、forward crosseditionトリガーが起動したアップグレード前のアプリケーションのユーザーが行った変更により、新しい行にトランスフォームされている可能性があります。しかし、予期せぬ変更によりトランスフォームされなかった行はすべてアップグレード前の表現のままです。古い行がすべて新しい行に確実にトランスフォームされるようにするには、アプリケーション・データに格納されている表で定義したトランスフォームを適用する必要があります。

トランスフォームを適用する方法には次の2通りがあります。

  • トランスフォームを定義しているトリガーを、表のすべての行に対して一度に1行ずつ起動します。

  • トリガーを起動するかわりに、トリガーで行われる内容をより速く処理するSQL文を実行し、そのトリガーに続くトリガーがあれば起動します。

    表全体を置換した場合、または新しい表を作成した場合は2番目の方法をお薦めします。

トランスフォームを適用する方法がどちらであっても、DBMS_SQL.PARSEプロシージャ、またはDBMS_PARALLEL_EXECUTEパッケージのサブプログラムを起動します。大量のデータがある場合は2番目の方法をお薦めします。このサブプログラムを使用すると、大容量の表のデータを並列で増分的に更新することができます。これは次の2つの手順で行われます。

  1. 表の行をグループ化して小さなチャンクに分けます。

  2. 必要なUPDATE文を並列でチャンクに適用し、1チャンクの処理が終了するたびにコミットします。

この利点は次のとおりです。

  • 表全体のロックではなく、相対的に短い時間で一度に1セットの行のみをロックする。

  • 操作全体が完了する前に問題が発生してもそれまでに処理した内容が失われない。

DBMS_SQL.PARSEプロシージャとDBMS_PARALLEL_EXECUTEサブプログラムの両方で、apply_crossedition_triggerfire_apply_triggerおよびsql_stmtの実際のパラメータ値は次に示すように同じです。

  • apply_crossedition_triggerには、適用されるトランスフォームを定義するforward crosseditionトリガーの名前を指定します。

  • 表のすべての行に対して一度に1行ずつトリガーを起動するには、次のようにします。

    • fire_apply_triggerの値にTRUEを指定します。

    • sql_stmtには、起動するforward crosseditionトリガーの選択以外に重要な影響を及ぼさないSQL文を指定します。たとえば、一部の列を各行の既存の値に設定するUPDATE文を指定します。

  • トリガーで行われる内容を処理するSQL文を実行し、そのトリガーに続くトリガーがあれば起動します。

    • fire_apply_triggerの値にFALSEを指定します。

    • sql_stmtには、forward crosseditionトリガーの処理内容をより速く行うSQL文を指定します。たとえば、1つ以上のPL/SQLサブプログラムをコールするPL/SQL無名ブロックを指定します。


参照:

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

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


更新内容の消失の防止

トランスフォームの適用中に更新内容が消失するのを防ぐには、次の手順を使用します。

  1. crosseditionトリガーを有効化します。

  2. 影響を受ける表への保留中の変更がコミットまたはロールバックされるまで待機します。

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

  3. トランスフォームを適用します。


注意:

このシナリオでは、forward crosseditionトリガーが変更するのはそれが定義された表のみですが、リスクを説明するには十分です。crosseditionトリガーがまだ有効になっていないときに、セッション1がUPDATE文を表に対して発行し、次にセッション2がcrosseditionトリガーを有効にし、すぐにトランスフォームを適用するとします。

セッション1とセッション2の両方が同じ行(行n)を変更しようとすると競合状態が発生する可能性があります。どちらのセッションが先に行nに到達するかは運次第です。最初に到達したセッションがその変更をコミットしてロックを解放するまで、2番目に行nに到達したセッションは待機する必要があるとしても、両方の更新は成功します。

問題は、セッション2が競合に勝った場合に起こります。そのSQL文はトリガーが有効になった後にコンパイルされたため、その文を実装するプログラムはトリガー・アクションも実装します。そのため、目的のアップグレード後の列の値は列nに設定されます。ここでセッション1が行nに到達しました。このSQL文はトリガーが有効になる前にコンパイルされたため、この文を実装するプログラムはトリガー・アクションを実装しません。そのため、セッション2がアップグレード後の列に設定した値は変更されず、セッション1が行nを更新する前のソース列の値を反映します。つまり、セッション1の更新の目的の副作用が消失します。


crosseditionトリガーの削除

crosseditionトリガーを削除するには、DROP TRIGGER文を使用します。詳細は『Oracle Database PL/SQL言語リファレンス』を参照してください。また、DROP EDITION文でCASCADE句を使用して、これらが実であるエディションを削除することにより、crosseditionトリガーを削除できます。エディションの削除の詳細は、「エディションの削除」を参照してください。

crosseditionトリガーは次の場合に削除します。

  • アプリケーション・アップグレードをロールバックしている(アップグレード後のエディションを削除している)場合。

    アップグレード後のエディションを削除する前に、新しい列の制約をすべて無効化、または削除する必要があります。

  • アプリケーションのアップグレードが完了し、すべてのユーザーがアップグレード後のエディションを使用できるようにしている場合。

    すべてのセッションでアップグレード後のエディションが使用されている場合は、forward crosseditionトリガーを削除できます。ただし、reverse crosseditionトリガーを削除する前に、古い列の制約をすべて無効化、または削除する必要があります。

制約を無効化または削除するには、ALTER TABLE文にDISABLE CONSTRAINTまたはDROP CONSTRAINT句を付けて使用します。ALTER TABLE文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

エディション、エディショニング・ビュー、crosseditionトリガーの情報の表示

表19-1および表19-2に、静的データ・ディクショナリ・ビューを示します。各ビューには、それぞれエディションとエディショニング・ビューの情報が表示されます。各表のビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

トリガーの情報を表示する静的データ・ディクショナリ・ビューは、『Oracle Databaseリファレンス』を参照してください。静的データ・ディクショナリ・ビューに示されるcrosseditionトリガーは、セッション・エディションの実オブジェクトです。

実行される一連のcrosseditionトリガーが異なる場合、子カーソルを共有することはできません。動的パフォーマンス・ビューV$SQL_SHARED_CURSORおよびGV$SQL_SHARED_CURSORには、これに該当するかどうかを示すCROSSEDITION_TRIGGER_MISMATCH列があります。V$SQL_SHARED_CURSORの詳細は、『Oracle Databaseリファレンス』を参照してください。

表19-1 エディション情報を含む*_ディクショナリ・ビュー

ビュー 説明

*_EDITIONS

データベースのすべてのエディションを示します。

*_EDITION_COMMENTS

データベースのすべてのエディションに関連付けられたコメントを示します。

*_OBJECTS

セッション・エディションで表示可能なデータベースのすべてのオブジェクト(実オブジェクトまたは継承オブジェクト)を示します。

*_OBJECTS_AE

すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。

*_ERRORS

セッション・エディションのデータベース内のすべてのエラーを示します。

*_ERRORS_AE

すべてのエディションのデータベース内のすべてのエラーを示します。

*_USERS

データベースのすべてのユーザーを示します。エディションが有効になっているユーザーを表示するときに役立ちます。

*_SERVICES

データベースのすべてのサービスを示します。

Oracle Database 11gリリース2 (11.2.0.2)では、EDITIONS列にデフォルトの最初のセッション・エディションが表示されます。



注意:

*_OBJECTSおよび*_OBJECTS_AEに含まれる依存オブジェクトが、表18-2の操作によって無効化されるのは、次のいずれかの後のみです。
  • オブジェクトの参照(コンパイル中または実行中)

  • DBMS_UTILITY.COMPILE_SCHEMAの起動(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)

  • 任意のUTL_RECOMPサブプログラムの起動(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)


表19-2 エディショニング・ビュー情報を含む*_ディクショナリ・ビュー

ビュー 説明

*_VIEWS

エディショニング・ビューを含む、セッション・エディションで表示可能なデータベースのすべてのビュー(実ビューまたは継承ビュー)を示します。

*_EDITIONING_VIEWS

セッション・エディションで表示可能なデータベースのすべてのエディショニング・ビュー(実エディショニング・ビューまたは継承エディショニング・ビュー)を示します。エディショニング・ビューと実表の関係を表示するときに役立ちます。*_OBJECTS_AEと結合すると、さらに情報を得ることができます。

*_EDITIONING_VIEWS_AE

すべてのエディションにおけるデータベース内のすべてのエディショニング・ビューのすべての実オブジェクトを示します。

*_EDITIONING_VIEW_COLS

セッション・エディションで表示可能なデータベースのすべてのエディショニング・ビュー(実エディショニング・ビューまたは継承エディショニング・ビュー)の列を示します。エディショニング・ビューの列とマッピング先の表の列との関係を表示するときに役立ちます。*_OBJECTS_AEまたは*_TAB_COL(あるいは両方)と結合すると、さらに情報を得ることができます。

*_EDITIONING_VIEW_COLS_AE

すべてのエディションのデータベースにあるすべてのエディショニング・ビューの列を示します。


*_EDITIONING_VIEWSの各行は、*_VIEWSの1つの行と厳密に一致します。EDITIONING_VIEW = 'Y'*_VIEWSの各行は、*_EDITIONING_VIEWSの1つの行と厳密に一致します。したがって、次の例のWHERE句は冗長です。

SELECT ...
  FROM DBA_EDITIONING_VIEWS INNER JOIN DBA_VIEWS
  USING (OWNER, VIEW_NAME)
  WHERE EDITIONING_VIEW = 'Y'
  AND ...

*_EDITIONING_VIEWSの行と一致する*_VIEWSの行は、定義によりEDITIONING_VIEW = 'Y'を満たします。反対に、EDITIONING_VIEW = 'N'*_VIEWSの行に対応する行は*_ EDITIONING_VIEWSにはありません。

アプリケーションをアップグレードするためのエディションベースの再定義の使用

エディションベースの再定義を使用して、アプリケーションをオンラインでアップグレードするには、まず、アプリケーションを準備する必要があります。

  1. 該当するユーザーに対してエディションを有効化します。

    手順は、「ユーザーに対するエディションの有効化」を参照してください。

    この手順を行う理由は、この次の手順で作成するエディショニング・ビューを所有できるのは、エディションが有効化されているユーザーのみであるためです。

  2. エディショニング・ビューを使用するようにアプリケーションを準備します。

    手順については、「アプリケーションでのエディショニング・ビューの使用準備」を参照してください。

エディショニング・ビューを表示し、エディションベースの再定義を使用して、アプリケーションをオンラインで必要な回数、アップグレードすることができます。アップグレードのたびに、次のようにしてください。

内容は次のとおりです。

アプリケーションでのエディショニング・ビューの使用準備

1つ以上の表を使用するアプリケーションでは、エディショニング・ビューで各表がカバーされる必要があります。エディショニング・ビューは、次のすべての記述が正しい場合にのみ、表をカバーします。

  • アプリケーション内の通常オブジェクトはすべて、エディショニング・ビューを通じてのみ、表を参照できます。(通常オブジェクトは、エディショニング・ビューまたはcrosseditionトリガー以外のすべてのオブジェクトです。エディショニング・ビューとcrosseditionトリガーは表を参照する必要があります。)

  • アプリケーション・ユーザーは、表ではなく、エディショニング・ビューに対してのみオブジェクト権限を付与されます。

  • 仮想プライベート・データベース(VPD)ポリシーは、表ではなく、エディショニング・ビューにのみアタッチされます。(日常的な監査、およびファイングレイン監査(FGA)ポリシーは、表にのみアタッチされます。)

エディショニング・ビューが実オブジェクト化された場合、VPDポリシーのコピーは実オブジェクト化されたエディショニング・ビューにアタッチされます。(ポリシーは名前と、アタッチ先オブジェクトにより一意に識別されます。)ポリシー・ファンクションも実オブジェクト化されている場合、このポリシーのコピーは実オブジェクト化されたポリシー・ファンクションを使用します。それ以外の場合は元のポリシー・ファンクションを使用します。

VPDポリシーを示す静的なデータ・ディクショナリ・ビュー*_POLICIESは、エディションに応じて、異なる結果を表示することができます。


参照:

  • VPDポリシーに関する情報を示す静的データ・ディクショナリ・ビューを含め、VPDに関する詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

  • *_POLICIESの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。


既存のアプリケーションがエディショニング・ビューを使用していない場合は、使用する各表に対して次の手順を実行して、エディショニング・ビューを使用できるようにアプリケーションを準備します。

  1. 表に新しい名前を付けます(現在の表名をエディショニング・ビューに付けるためです)。

    新しい名前は、元の名前に関連したものとし、変更履歴を示すようにしてください。たとえば、元の表名がDataの場合、新しい表名をData_1とすることができます。

  2. (オプション)表の各列に新しい名前を付けます。

    このときも、新しい名前は、元の名前に関連したものとし、変更履歴を示すようにしてください。たとえば、NameおよびNumberName_1およびNumber_1のように変更できます。

    名前を変更した列に依存するトリガーはここで無効になります。詳細は、表18-2ALTER TABLE table RENAME columnの項目を参照してください。

  3. エディショニング・ビューを作成し、表の元の名前を付けます。

    手順は、「エディショニング・ビューの作成」を参照してください。

    エディショニング・ビューには表の元の名前が付けられるため、その表名を参照しているオブジェクトがエディショニング・ビューを参照するようになります。

  4. トリガーが表に定義されている場合は、トリガーを削除してから、作成時に使用したコードを再実行します。

    こうすることで、表に定義されていたトリガーが、エディショニング・ビューに対して定義されます。

  5. VPDポリシーが表にアタッチされている場合は、このポリシーとポリシー・ファンクションを削除してから、作成時に使用したコードを再実行します。

    これにより、表にアタッチされていたVPDポリシーが、エディショニング・ビューにアタッチされます。

  6. すべてのアプリケーション・ユーザーから、表に対するすべてのオブジェクト権限を取り消します。

    表に対し、どのアプリケーション・ユーザーがどのオブジェクト権限を持っているかを確認するには、次の問合せを使用します。

    SELECT GRANTEE, PRIVILEGE
    FROM DBA_TAB_PRIVS
    WHERE TABLE_NAME='table_name';
    
  7. 手順6で取り消された権限すべてについて、エディショニング・ビューで同じ権限を付与します。

  8. 表を参照するプライベート・シノニムを所有するユーザーに対してエディションを有効化し(手順については、「ユーザーに対するエディションの有効化」を参照)、これらのユーザーに、シノニムを再作成する必要があることを通知します。


注意:

この結果、表を参照するパブリック・シノニムはORA-00980で失敗するようになります。エディショニング・ビューでこれらを再作成することはできません(理由については、「参照されているオブジェクトの実オブジェクト化」を参照)。

エディションのみを使用するエディションベースの再定義の手順

次の手順は、再定義するすべてのオブジェクトのオブジェクト・タイプがエディション対応(定義は「エディション対応、およびエディション非対応スキーマ・オブジェクト・タイプ」を参照)である場合のみ使用します。表はエディション対応タイプではありません。

  1. 新しいエディションを作成します。

    手順は、「エディションの作成」を参照してください。

  2. 新しいエディションをセッション・エディションにします。

    手順は、「セッション・エディションの変更」を参照してください。

  3. アプリケーションのエディション・オブジェクトに必要な変更を行います。

  4. すべてのオブジェクトが有効であることを確認します。

    静的データ・ディクショナリ*_OBJECTS_AEを問い合せます。これは、すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。無効オブジェクトが残っている場合は、任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を使用して再コンパイルします。

  5. 変更内容が意図したように機能していることを確認します。

    機能している場合は、手順6に進みます。

    そうでない場合は、さらに変更を続ける(手順3に戻る)か、またはアプリケーション・アップグレードをロールバックします(手順については、「アプリケーション・アップグレードのロールバック」を参照)。

  6. 新しいエディション(アップグレードされたアプリケーション)をすべてのユーザーに対して使用可能にします。

    手順は、「すべてのユーザーに対してエディションを使用可能にする」を参照してください。

  7. 古いエディション(元のアプリケーション)をリタイアさせ、SYS以外のすべてのユーザーがアップグレードされたアプリケーションのみを使用するようにします。

    手順は、「エディションのリタイア」を参照してください。

例19-6は、ここで説明した手順を使用して、非常に単純なPL/SQLプロシージャを変更する方法を示します。

例19-6 非常に単純なプロシージャのエディションベースの再定義

  1. この例で使用するPL/SQLプロシージャを作成します。

    CREATE OR REPLACE PROCEDURE hello IS
    BEGIN
      DBMS_OUTPUT.PUT_LINE('Hello, edition 1.');
    END hello;
    /
    
  2. PL/SQLプロシージャを起動します。

    BEGIN hello(); END;
    /
    

    結果:

    Hello, edition 1.
     
    PL/SQL procedure successfully completed.
    
  3. プロシージャをエディションベースで再定義します。

    1. 新しいエディションを作成します。

      CREATE EDITION e2 AS CHILD OF ora$base;
      

      結果:

      Edition created.
      
    2. 新しいエディションをセッション・エディションにします。

      ALTER SESSION SET EDITION = e2;
      

      結果:

      Session altered.
      
    3. プロシージャを変更します。

      CREATE OR REPLACE PROCEDURE hello IS
      BEGIN
        DBMS_OUTPUT.PUT_LINE('Hello, edition 2.');
      END hello;
      /
      

      結果:

      Procedure created.
      
    4. 変更内容が意図したように機能していることを確認します。

      BEGIN hello(); END;
      /
      

      結果:

      Hello, edition 2.
      PL/SQL procedure successfully completed.
      
    5. すべてのユーザーが新しいエディションを使用できるようにします(システム権限が必要です)。

      ALTER DATABASE DEFAULT EDITION = e2;
      
    6. 古いエディションをリタイアさせます(システム権限が必要です)。

      権限受領者のリストを表示します。

      SELECT GRANTEE, PRIVILEGE
      FROM DBA_TAB_PRIVS
      WHERE TABLE_NAME = UPPER('ora$base')
      /
      

      結果:

      GRANTEE                        PRIVILEGE
      ------------------------------ ---------
      PUBLIC                         USE
       
      1 row selected.
      

      すべての権限受領者について、古いエディションの使用を取り消します。

      REVOKE USE ON EDITION ora$base FROM PUBLIC;
      

エディショニング・ビューを使用するエディションベースの再定義の手順

1つ以上の表の構造を変更するとき、その間に他のユーザーがそれらの表のデータを変更できなくてもよい場合のみ、次の手順を使用します。

  1. 新しいエディションを作成します。

    手順は、「エディションの作成」を参照してください。

  2. 新しいエディションをセッション・エディションにします。

    手順は、「セッション・エディションの変更」を参照してください。

  3. 新しいエディションで、エディショニング・ビューが読取り専用の場合は、読取り/書込みに変更します。

    手順は、「エディショニング・ビューの書込み可能性の変更」を参照してください。

  4. 新しいエディションを除くすべてのエディションで、エディショニング・ビューを読取り専用にします。

  5. アプリケーションのオブジェクトに必要な変更を行います。

  6. すべてのオブジェクトが有効であることを確認します。

    静的データ・ディクショナリ*_OBJECTS_AEを問い合せます。これは、すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。無効オブジェクトが残っている場合は、任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を使用して再コンパイルします。

  7. 変更内容が意図したように機能していることを確認します。

    機能している場合は、手順8に進みます。

    そうでない場合は、さらに変更を続ける(手順5に戻る)か、またはアプリケーション・アップグレードをロールバックします(手順については、「アプリケーション・アップグレードのロールバック」を参照)。

  8. アップグレードされたアプリケーションをすべてのユーザーに対して使用可能にします。

    手順は、「すべてのユーザーに対してエディションを使用可能にする」を参照してください。

  9. 古いエディション(元のアプリケーション)をリタイアさせ、SYS以外のすべてのユーザーがアップグレードされたアプリケーションのみを使用するようにします。

    手順は、「エディションのリタイア」を参照してください。

crosseditionトリガーを使用するエディションベースの再定義の手順

1つ以上の表の構造を変更するとき、その間に他のユーザーがそれらの表のデータを変更する必要がある場合のみ、次の手順を使用します。

  1. 新しいエディションを作成します。

    手順は、「エディションの作成」を参照してください。

  2. 新しいエディションをセッション・エディションにします。

    手順は、「セッション・エディションの変更」を参照してください。

  3. アプリケーションのオブジェクトに永続的な変更を行います。

    たとえば、表に新しい列を追加し、新しい永続サブプログラムを作成します。

    ここで、変更したオブジェクトに依存するオブジェクトが無効になることがあります。詳細は、表18-2を参照してください。

  4. すべてのオブジェクトが有効であることを確認します。

    静的データ・ディクショナリ*_OBJECTS_AEを問い合せます。これは、すべてのエディションにおけるデータベース内のすべての実オブジェクトを示します。無効オブジェクトが残っている場合は、任意のUTL_RECOMPサブプログラム(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)を使用して再コンパイルします。

  5. 一時オブジェクト、すなわちcrosseditionトリガー(無効状態)とトリガーで必要なサブプログラムを作成します。

    手順は、「crosseditionトリガーの作成」を参照してください。

    reverse crosseditionトリガーが必要になるのは、手順10(オプション)を実行する場合のみです。

  6. crosseditionトリガーが正常にコンパイルされたら、crosseditionトリガーを有効にします。

    ALTER TRIGGER文にENABLEオプションを付けて使用します。この文の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

  7. 保留中の変更がコミットまたはロールバックされるまで待機します。

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

  8. トランスフォームを適用します。

    手順については、「アップグレード前の表現をアップグレード後の表現に変換」を参照してください。


    注意:

    この手順が既存の行を処理した後で、祖先エディションのユーザーが同じ行のデータを更新、挿入または削除するかどうかを予測することはできません。

  9. 変更内容が意図したように機能していることを確認します。

    機能している場合は、手順10に進みます。

    そうでない場合は、さらに変更を続ける(手順3に戻る)か、またはアプリケーション・アップグレードをロールバックします(手順については、「アプリケーション・アップグレードのロールバック」を参照)。

  10. (オプション)セッション・エディションのUSE権限を、アップグレードしたアプリケーションの初期のユーザーに付与します。

    手順は、「一部のユーザーに対してエディションを使用可能にする」を参照してください。

  11. アップグレードされたアプリケーションをすべてのユーザーに対して使用可能にします。

    手順は、「すべてのユーザーに対してエディションを使用可能にする」を参照してください。

  12. 制約を無効化、または削除してから、croseditionトリガーを削除します。

    手順は、「crosseditionトリガーの削除」を参照してください。

  13. 古いエディション(元のアプリケーション)をリタイアさせ、SYS以外のすべてのユーザーがアップグレードされたアプリケーションのみを使用するようにします。

    手順は、「エディションのリタイア」を参照してください。

アプリケーション・アップグレードのロールバック

アプリケーション・アップグレードをロールバックするには、次のようにします。

  1. セッション・エディションを、アップグレード用に作成した新しいエディション以外のものに変更します。

    手順は、「セッション・エディションの変更」を参照してください。

  2. アップグレード用に作成した新しいエディションを削除します。

    手順は、「エディションの削除」を参照してください。

  3. アップグレード中に、新しい表の列を作成した場合、これらの列が占めていた領域を再利用します(手順については、「使用されていない表の列が占める領域の再利用」を参照)。

使用されていない表の列が占める領域の再利用

新しい表の列を作成したアップグレードをロールバックする場合

未使用の列が占めている領域を再利用するには、次のようにします。

  1. 未使用の列の値をNULLに設定します。

    この操作を行っている間に、他のユーザーをロックアウトしてしまわないようにするには、DBMS_PARALLEL_EXECUTEプロシージャを使用します(『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照)。

  2. 未使用の列をUNUSEDに設定します。

    ALTER TABLE文(『Oracle Database SQL言語リファレンス』を参照)をSET UNUSED句(『Oracle Database SQL言語リファレンス』を参照)とともに使用します。

  3. 表を縮小します。

    ALTER TABLE文(『Oracle Database SQL言語リファレンス』を参照)をSHRINK SPACE句(『Oracle Database SQL言語リファレンス』を参照)とともに使用します。

例: アプリケーションをアップグレードするためのエディションベースの再定義の使用

この例は、エディション、エディショニング・ビュー、forward crosseditionトリガーおよびreverse crosseditionトリガーを使用します。

内容は次のとおりです。


注意:

アプリケーションのアップグレードにエディションベースの再定義を使用する前に、このアプリケーションで使用されるスキーマすべてについてエディションを有効化する必要があります。手順は、「ユーザーに対するエディションの有効化」を参照してください。

既存のアプリケーション

既存のアプリケーション(アップグレード対象のアプリケーション)は、トリガーが定義された1つの表で構成されています。このアプリケーションは例19-7に従って作成されたものです。

例19-7 既存のアプリケーションの作成

  1. 表を作成します。

    CREATE TABLE Contacts(
      ID            NUMBER(6,0) CONSTRAINT Contacts_PK PRIMARY KEY,
      Name          VARCHAR2(47),
      Phone_Number  VARCHAR2(20)
    );
    
  2. 表にデータを移入します(例は示されていません)。

  3. 表にトリガーを作成する準備をします。

    ALTER TABLE Contacts ENABLE VALIDATE CONSTRAINT Contacts_PK;
     
    DECLARE Max_ID INTEGER;
    BEGIN
      SELECT MAX(ID) INTO Max_ID FROM Contacts;
      EXECUTE IMMEDIATE '
        CREATE SEQUENCE Contacts_Seq
          START WITH '||To_Char(Max_ID + 1);
    END;
    /
    
  4. トリガーを作成します。

    CREATE TRIGGER Contacts_BI
      BEFORE INSERT ON Contacts FOR EACH ROW
    BEGIN
      :NEW.ID := Contacts_Seq.NEXTVAL;
    END;
    /
    

例19-8は、データ移入後の表Contactsを示しています。

例19-8 既存の表のデータの表示

問合せ:

SELECT * FROM Contacts
ORDER BY Name;
 

結果:

        ID NAME                                            PHONE_NUMBER
---------- ----------------------------------------------- --------------------
       174 Abel, Ellen                                     011.44.1644.429267
       166 Ande, Sundar                                    011.44.1346.629268
       130 Atkinson, Mozhe                                 650.124.6234
       105 Austin, David                                   590.423.4569
       204 Baer, Hermann                                   515.123.8888
       116 Baida, Shelli                                   515.127.4563
       167 Banda, Amit                                     011.44.1346.729268
       172 Bates, Elizabeth                                011.44.1343.529268
       192 Bell, Sarah                                     650.501.1876
       151 Bernstein, David                                011.44.1344.345268
       129 Bissot, Laura                                   650.124.5234
       169 Bloom, Harrison                                 011.44.1343.829268
       185 Bull, Alexis                                    650.509.2876
       187 Cabrio, Anthony                                 650.509.4876
       148 Cambrault, Gerald                               011.44.1344.619268
       154 Cambrault, Nanette                              011.44.1344.987668
       110 Chen, John                                      515.124.4269
       ...
       120 Weiss, Matthew                                  650.123.1234
       200 Whalen, Jennifer                                515.123.4444
       149 Zlotkey, Eleni                                  011.44.1344.429018

107 rows selected.

Contactsを再定義する必要があるとします。Name列をFirst_Name列とLast_Name列で置換し、Country_Code列を追加します。また、この構造変更を行う際に、他のユーザーがContactsのデータを変更できることが必要です。

エディションベースの再定義のすべての機能が必要になります。つまり、エディション(常に必要)、エディショニング・ビュー(表を再定義するため)、およびcrosseditionトリガー(表の再定義中に他のユーザーが表のデータを変更する必要があるため)です。

アプリケーションでのエディショニング・ビューの使用準備

例19-8は、新しいエディションでエディショニング・ビューを作成する方法を示します。Contacts表を再定義している間、エディショニング・ビューを使用して他のユーザーがその表にアクセスします。

例19-9 既存の表のエディショニング・ビューの作成

  1. 表に新しい名前を付けます(現在の表名をエディショニング・ビューに付けるためです)。

    ALTER TABLE Contacts RENAME TO Contacts_Table;
    
  2. (オプション)表の列に新しい名前を付けます。

    ALTER TABLE Contacts_Table
      RENAME COLUMN Name TO Name_1;
    
    ALTER TABLE Contacts_Table
      RENAME COLUMN Phone_Number TO Phone_Number_1;
    
  3. エディショニング・ビューを作成します。

    CREATE OR REPLACE EDITIONING VIEW Contacts AS
      SELECT
        ID                 ID,
        Name_1             Name,
        Phone_Number_1     Phone_Number
      FROM Contacts_Table;
    
  4. トリガーContacts_BIを表からエディショニング・ビューに移動します。

    DROP TRIGGER Contacts_BI;
     
    CREATE TRIGGER Contacts_BI
      BEFORE INSERT ON Contacts FOR EACH ROW
    BEGIN
      :NEW.ID := Contacts_Seq.NEXTVAL;
    END;
    /
    

アプリケーションをアップグレードするためのエディションベースの再定義の使用

例19-10では、既存のアプリケーションをアップグレードするエディションを作成し、新しいエディションをセッション・エディションにして、新しいエディションが実際にセッション・エディションであることをチェックする方法を示します。

例19-10 アプリケーションをアップグレードするエディションの作成

  1. 新しいエディションを作成します。

    CREATE EDITION Post_Upgrade AS CHILD OF Ora$Base;
    
  2. 新しいエディションをセッション・エディションにします。

    ALTER SESSION SET EDITION = Post_Upgrade;
    
  3. セッション・エディションをチェックします。

    SELECT
    SYS_CONTEXT('Userenv', 'Current_Edition_Name') "Current_Edition"
    FROM DUAL;
    

    結果:

    Current_Edition
    -----------------------------------------------------------------------------
    POST_UPGRADE
     
    1 row selected.
    

例19-11は、Post_Upgradeエディションで、物理表に新しい列を追加し、列の追加により無効化されたトリガーを再コンパイルする方法を示します。エディショニング・ビューContactsが表の列を適切な論理名で選択するように、このエディショニング・ビューを置換する方法を示します。

例19-11 表の変更とエディショニング・ビューの置換

  1. 物理表に新しい列を追加します。

    ALTER TABLE Contacts_Table ADD (
      First_Name_2     varchar2(20),
      Last_Name_2      varchar2(25),
      Country_Code_2   varchar2(20),
      Phone_Number_2   varchar2(20)
    );
    

    (これは非ブロック化DDLです。)

  2. 無効化されたトリガーを再コンパイルします。

    ALTER TRIGGER Contacts_BI COMPILE REUSE SETTINGS;
    
  3. エディショニング・ビューを置換して、このエディショニング・ビューが置換列を適切な論理名で選択するようにします。

    CREATE OR REPLACE EDITIONING VIEW Contacts AS
      SELECT
        ID                 ID,
        First_Name_2       First_Name,
        Last_Name_2        Last_Name,
        Country_Code_2     Country_Code,
        Phone_Number_2     Phone_Number
      FROM Contacts_Table;
    

例19-12は、Post_Upgradeエディションで、forward crosseditionトリガーにより使用されるプロシージャを2つ作成し、無効な状態のforward crosseditionトリガーとreverse crosseditionトリガーの両方を作成してから、これらを有効化する方法を示します。

例19-12 crosseditionトリガーの作成と有効化

  1. forward crosseditionトリガーにより使用される1つ目のプロシージャを作成します。

    CREATE OR REPLACE PROCEDURE Set_First_And_Last_Name (
      Name        IN  VARCHAR2,
      First_Name  OUT VARCHAR2,
      Last_Name   OUT VARCHAR2)
    IS
      Comma_Pos NUMBER := INSTR(Name, ',');
    BEGIN
      IF Comma_Pos IS NULL OR Comma_Pos < 2 THEN
        RAISE Program_Error;
      END IF;
     
      Last_Name := SUBSTR(Name, 1, Comma_Pos-1);
      Last_Name := RTRIM(Ltrim(Last_Name));
     
      First_Name := SUBSTR(Name, Comma_Pos+1);
      First_Name := RTRIM(LTRIM(First_Name));
    END Set_First_And_Last_Name;
    /
    
  2. forward crosseditionトリガーにより使用される2つ目のプロシージャを作成します。

    CREATE OR REPLACE PROCEDURE Set_Country_Code_And_Phone_No (
      Phone_Number     IN  VARCHAR2,
      Country_Code     OUT VARCHAR2,
      Phone_Number_V2  OUT VARCHAR2)
    IS
      Char_To_Number_Error EXCEPTION;
      PRAGMA EXCEPTION_INIT(Char_To_Number_Error, -06502);
      Bad_Phone_Number EXCEPTION;
      Nmbr VARCHAR2(30) := REPLACE(Phone_Number, '.', '-');
     
      FUNCTION Is_US_Number(Nmbr IN VARCHAR2)
        RETURN BOOLEAN
      IS
        Len NUMBER := LENGTH(Nmbr);
        Dash_Pos NUMBER := INSTR(Nmbr, '-');
        n PLS_INTEGER;
      BEGIN
        IF Len IS NULL OR Len <> 12 THEN
          RETURN FALSE;
        END IF;
        IF Dash_Pos IS NULL OR Dash_Pos <> 4 THEN
          RETURN FALSE;
        END IF;
        BEGIN
          n := TO_NUMBER(SUBSTR(Nmbr, 1, 3));
        EXCEPTION WHEN Char_To_Number_Error THEN
          RETURN FALSE;
        END;
     
        Dash_Pos := INSTR(Nmbr, '-', 5);
     
        IF Dash_Pos IS NULL OR Dash_Pos <> 8 THEN
          RETURN FALSE;
        END IF;
     
        BEGIN
          n := TO_NUMBER(SUBSTR(Nmbr, 5, 3));
        EXCEPTION WHEN Char_To_Number_Error THEN
          RETURN FALSE;
        END;
     
        BEGIN
          n := TO_NUMBER(SUBSTR(Nmbr, 9));
        EXCEPTION WHEN Char_To_Number_Error THEN
          RETURN FALSE;
        END;
     
        RETURN TRUE;
      END Is_US_Number;
     
    BEGIN
      IF Nmbr LIKE '011-%' THEN
        DECLARE
          Dash_Pos NUMBER := INSTR(Nmbr, '-', 5);
        BEGIN
          Country_Code := '+'|| TO_NUMBER(SUBSTR(Nmbr, 5, Dash_Pos-5));
          Phone_Number_V2 := SUBSTR(Nmbr, Dash_Pos+1);
        EXCEPTION WHEN Char_To_Number_Error THEN
          raise Bad_Phone_Number;
        END;
      ELSIF Is_US_Number(Nmbr) THEN
        Country_Code := '+1';
        Phone_Number_V2 := Nmbr;
      ELSE
        RAISE Bad_Phone_Number;
      END IF;
    EXCEPTION WHEN Bad_Phone_Number THEN
      Country_Code := '+0';
      Phone_Number_V2 := '000-000-0000';
    END Set_Country_Code_And_Phone_No;
    /
    
  3. 無効な状態のforward crosseditionトリガーを作成します。

    CREATE OR REPLACE TRIGGER Contacts_Fwd_Xed
      BEFORE INSERT OR UPDATE ON Contacts_Table
      FOR EACH ROW
      FORWARD CROSSEDITION
      DISABLE
    BEGIN
      Set_First_And_Last_Name(
        :NEW.Name_1,
        :NEW.First_Name_2,
        :NEW.Last_Name_2
      );
      Set_Country_Code_And_Phone_No(
        :NEW.Phone_Number_1,
        :NEW.Country_Code_2,
        :NEW.Phone_Number_2
      );
    END Contacts_Fwd_Xed;
    /
    
  4. forward crosseditionトリガーを有効化します。

    ALTER TRIGGER Contacts_Fwd_Xed ENABLE;
    
  5. 無効な状態のreverse crosseditionトリガーを作成します。

    CREATE OR REPLACE TRIGGER Contacts_Rvrs_Xed
      BEFORE INSERT OR UPDATE ON Contacts_Table
      FOR EACH ROW
      REVERSE CROSSEDITION
      DISABLE
    BEGIN
      :NEW.Name_1 := :NEW.Last_Name_2||', '||:NEW.First_Name_2;
      :NEW.Phone_Number_1 :=
      CASE :New.Country_Code_2
        WHEN '+1' THEN
          REPLACE(:NEW.Phone_Number_2, '-', '.')
        ELSE
          '011.'||LTRIM(:NEW.Country_Code_2, '+')||'.'||
          REPLACE(:NEW.Phone_Number_2, '-', '.')
      END;
    END Contacts_Rvrs_Xed;
    /
    
  6. reverse crosseditionトリガーを有効化します。

    ALTER TRIGGER Contacts_Rvrs_Xed ENABLE;
    
  7. 保留中の変更がコミットまたはロールバックされるまで待機します。

    DECLARE
      scn              NUMBER  := NULL;
      timeout CONSTANT INTEGER := NULL;
    BEGIN
      IF NOT DBMS_UTILITY.WAIT_ON_PENDING_DML(Tables  => 'Contacts_Table',
                                              timeout => timeout,
                                              scn     => scn)
      THEN
        RAISE_APPLICATION_ERROR(-20000,
         'Wait_On_Pending_DML() timed out. CETs were enabled before SCN: '||SCN);
      END IF;
    END;
    /
    

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

例19-13は、Post_Upgradeエディションで、トランスフォームを適用する方法を示します。

例19-13 トランスフォームの適用

DECLARE
  c NUMBER := DBMS_SQL.OPEN_CURSOR();
  x NUMBER;
BEGIN
  DBMS_SQL.PARSE(
    c                          => c,
    Language_Flag              => DBMS_SQL.NATIVE,
    Statement                  => 'UPDATE Contacts_Table SET ID = ID',
    Apply_Crossedition_Trigger => 'Contacts_Fwd_Xed'
  );
  x := DBMS_SQL.EXECUTE(c);
  DBMS_SQL.CLOSE_CURSOR(c);
  COMMIT;
END;
/
 

例19-14は、Post_Upgradeエディションで、変更が意図したとおりに機能しているかどうかをチェックする方法を示します。例19-14例19-8を比較してください。

例19-14 変更された表のデータ表示

  1. 列が読みやすくなるように書式設定します。

    COLUMN ID FORMAT 999
    COLUMN Last_Name FORMAT A15
    COLUMN First_Name FORMAT A15
    COLUMN Country_Code FORMAT A12
    COLUMN Phone_Number FORMAT A12
    
  2. 問合せ:

    SELECT * FROM Contacts
    ORDER BY Last_Name;
    

    結果:

      ID FIRST_NAME      LAST_NAME       COUNTRY_CODE PHONE_NUMBER
    ---- --------------- --------------- ------------ ------------
     174 Ellen           Abel            +44          1644-429267
     166 Sundar          Ande            +44          1346-629268
     130 Mozhe           Atkinson        +1           650-124-6234
     105 David           Austin          +1           590-423-4569
     204 Hermann         Baer            +1           515-123-8888
     116 Shelli          Baida           +1           515-127-4563
     167 Amit            Banda           +44          1346-729268
     172 Elizabeth       Bates           +44          1343-529268
     192 Sarah           Bell            +1           650-501-1876
     151 David           Bernstein       +44          1344-345268
     129 Laura           Bissot          +1           650-124-5234
     169 Harrison        Bloom           +44          1343-829268
     185 Alexis          Bull            +1           650-509-2876
     187 Anthony         Cabrio          +1           650-509-4876
     154 Nanette         Cambrault       +44          1344-987668
     148 Gerald          Cambrault       +44          1344-619268
     110 John            Chen            +1           515-124-4269
           ...
     120 Matthew         Weiss           +1           650-123-1234
     200 Jennifer        Whalen          +1           515-123-4444
     149 Eleni           Zlotkey         +44          1344-429018
     
    107 rows selected.
    

変更が意図どおりに機能した場合は、「crosseditionトリガーを使用するエディションベースの再定義の手順」の手順10から13を実行することができます。