ヘッダーをスキップ
Oracle® Streams概要および管理
11gリリース2 (11.2)
B61351-03
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

17 Oracle Streams情報コンシュームの管理

適用プロセスは、Oracle Streams環境で暗黙的に情報をコンシュームします。論理変更レコード(LCR)およびユーザー・メッセージを特定のキューからデキューして、各メッセージを直接適用するか、パラメータとしてユーザー定義プロシージャに渡します。

次の各項では、Oracle Streamsの適用プロセスの管理について説明します。

この章で説明する各タスクは、特に明記されていないかぎり、適切な権限を付与されているOracle Streams管理者が完了する必要があります。


関連項目:


適用プロセスの起動

既存の適用プロセスを起動するには、DBMS_APPLY_ADMパッケージのSTART_APPLYプロシージャを実行します。たとえば、次のプロシージャでは適用プロセスstrm01_applyが起動されます。

BEGIN
  DBMS_APPLY_ADM.START_APPLY(
    apply_name => 'strm01_apply');
END;
/

関連項目:

Oracle Enterprise Managerを使用した適用プロセスの起動については、Oracle Database 2日でデータ・レプリケーションおよび統合ガイドを参照

適用プロセスの停止

既存の適用プロセスを停止するには、DBMS_APPLY_ADMパッケージのSTOP_APPLYプロシージャを実行します。たとえば、次のプロシージャでは適用プロセスstrm01_applyが停止されます。

BEGIN
  DBMS_APPLY_ADM.STOP_APPLY(
    apply_name => 'strm01_apply');
END;
/

関連項目:

Oracle Enterprise Managerでの適用プロセスの停止方法については、Oracle Database 2日でデータ・レプリケーションおよび統合ガイドを参照

適用プロセスのルール・セットの管理

この項では、次のタスクの実行手順を説明します。

適用プロセスのルール・セットの指定

適用プロセスには、1つのポジティブ・ルール・セットおよび1つのネガティブ・ルール・セットを指定できます。適用プロセスでは、メッセージは、ポジティブ・ルール・セットの少なくとも1つのルールについてTRUEと評価される場合は適用され、ネガティブ・ルール・セットの少なくとも1つのルールについてTRUEと評価される場合は廃棄されます。ネガティブ・ルール・セットは、ポジティブ・ルール・セットの前に評価されます。

適用プロセスのポジティブ・ルール・セットの指定

既存のルール・セットをポジティブ・ルール・セットとして既存の適用プロセスに指定するには、ALTER_APPLYプロシージャのrule_set_nameパラメータを使用します。このプロシージャは、DBMS_APPLY_ADMパッケージに含まれています。

たとえば、次のプロシージャでは、適用プロセスstrm01_applyのポジティブ・ルール・セットがstrm02_rule_setに設定されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name    => 'strm01_apply',
    rule_set_name => 'strmadmin.strm02_rule_set');
END;
/

適用プロセスのネガティブ・ルール・セットの指定

既存のルールセットをネガティブ・ルール・セットとして既存の適用プロセスに指定するには、ALTER_APPLYプロシージャのnegative_rule_set_nameパラメータを使用します。このプロシージャは、DBMS_APPLY_ADMパッケージに含まれています。

たとえば、次のプロシージャでは、適用プロセスstrm01_applyのネガティブ・ルール・セットがstrm03_rule_setに設定されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name             => 'strm01_apply',
    negative_rule_set_name => 'strmadmin.strm03_rule_set');
END;
/

適用プロセスのルール・セットへのルールの追加

適用プロセスルール・セットルールを追加するには、次のプロシージャのいずれかを実行します。

  • DBMS_STREAMS_ADM.ADD_TABLE_RULES

  • DBMS_STREAMS_ADM.ADD_SUBSET_RULES

  • DBMS_STREAMS_ADM.ADD_SCHEMA_RULES

  • DBMS_STREAMS_ADM.ADD_GLOBAL_RULES

ADD_SUBSET_RULESプロシージャ以外のこれらのプロシージャでは、適用プロセスのポジティブ・ルール・セットまたはネガティブ・ルール・セットにルールを追加できます。ADD_SUBSET_RULESプロシージャでは、適用プロセスのポジティブ・ルール・セットにのみルールを追加できます。

適用プロセスのポジティブ・ルール・セットへのルールの追加

次の例では、DBMS_STREAMS_ADMパッケージのADD_TABLE_RULESプロシージャを実行して、適用プロセスstrm01_applyのポジティブ・ルール・セットにルールを追加します。

BEGIN
  DBMS_STREAMS_ADM.ADD_TABLE_RULES(
    table_name       => 'hr.departments',
    streams_type     => 'apply',
    streams_name     => 'strm01_apply',
    queue_name       => 'streams_queue',
    include_dml      => TRUE,
    include_ddl      => TRUE,
    source_database  => 'dbs1.example.com',
    inclusion_rule   => TRUE);
END;
/

このプロシージャを実行すると、次のアクションが実行されます。

  • ルールが1つ作成されます。このルールは、hr.departments表に対するDML変更の結果を含む行LCRについてTRUEと評価されます。ルール名はシステムによって生成されます。

  • ルールが1つ作成されます。このルールは、hr.departments表に対するDDL変更を含むDDL LCRについてTRUEと評価されます。ルール名はシステムによって生成されます。

  • どちらのルールも、dbs1.example.comソース・データベースで変更が発生したLCRに対してのみTRUEと評価されるように指定されます。

  • inclusion_ruleパラメータがTRUEに設定されているため、そのルールは適用プロセスに関連付けられたポジティブ・ルール・セットに追加されます。

適用プロセスのネガティブ・ルール・セットへのルールの追加

次の例では、DBMS_STREAMS_ADMパッケージのADD_TABLE_RULESプロシージャを実行して、適用プロセスstrm01_applyのネガティブ・ルール・セットにルールを追加します。

BEGIN
  DBMS_STREAMS_ADM.ADD_TABLE_RULES(
    table_name       => 'hr.regions',
    streams_type     => 'apply',
    streams_name     => 'strm01_apply',
    queue_name       => 'streams_queue',
    include_dml      => TRUE,
    include_ddl      => TRUE,
    source_database  => 'dbs1.example.com',
    inclusion_rule   => FALSE);
END;
/

このプロシージャを実行すると、次のアクションが実行されます。

  • ルールが1つ作成されます。このルールは、hr.regions表に対するDML変更の結果を含む行LCRについてTRUEと評価されます。ルール名はシステムによって生成されます。

  • ルールが1つ作成されます。このルールは、hr.regions表に対するDDL変更を含むDDL LCRについてTRUEと評価されます。ルール名はシステムによって生成されます。

  • どちらのルールも、dbs1.example.comソース・データベース で変更が発生したLCRに対してのみ TRUEと評価されるように指定されます。

  • inclusion_ruleパラメータがFALSEに設定されているため、そのルールは適用プロセスに関連付けられたネガティブ・ルール・セットに追加されます。

適用プロセスのルール・セットからのルールの削除

既存の適用プロセスルール・セットからルールを削除するには、DBMS_STREAMS_ADMパッケージのREMOVE_RULEプロシージャを実行します。たとえば、次のプロシージャでは、適用プロセスstrm01_applyポジティブ・ルール・セットからルールdepartments3が削除されます。

BEGIN
  DBMS_STREAMS_ADM.REMOVE_RULE(
    rule_name        => 'departments3',
    streams_type     => 'apply',
    streams_name     => 'strm01_apply',
    drop_unused_rule => TRUE,
    inclusion_rule   => TRUE);
END;
/

この例では、REMOVE_RULEプロシージャのdrop_unused_ruleパラメータがTRUEに設定されています。これはデフォルトの設定です。したがって、削除するルールが他のどのルール・セットにも含まれていなければ、そのルールはデータベースから削除されます。drop_unused_ruleパラメータがFALSEに設定されている場合、ルールはルール・セットから削除されますが、他のどのルール・セットにも含まれていない場合でも、データベースからは削除されません。

inclusion_ruleパラメータをFALSEに設定すると、REMOVE_RULEプロシージャによって、適用プロセスのポジティブ・ルール・セットからではなく、ネガティブ・ルール・セットからルールが削除されます。

適用プロセスのルール・セットからすべてのルールを削除するには、REMOVE_RULEプロシージャの実行時にrule_nameパラメータにNULLを指定します。

適用プロセスのルール・セットの削除

既存の適用プロセスから ルール・セットを削除するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャを使用します。このプロシージャでは、ポジティブ・ルール・セットまたはネガティブ・ルール・セット、あるいはその両方を削除できます。適用プロセスのポジティブ・ルール・セットを削除するには、remove_rule_setパラメータにTRUEを設定します。適用プロセスのネガティブ・ルール・セットを削除するには、remove_negative_rule_setパラメータにTRUEを設定します。

たとえば、次のプロシージャでは、適用プロセスstrm01_applyからポジティブ・ルール・セットとネガティブルール・セットの両方が削除されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name               => 'strm01_apply',
    remove_rule_set          => TRUE,
    remove_negative_rule_set => TRUE);
END;
/

注意:

バッファ・キューからメッセージをデキューする適用プロセスに、ポジティブ・ルール・セットまたはネガティブ・ルール・セットがない場合、適用プロセスによって、キュー内のすべての取得LCRがデキューされます。同様に、永続キューからメッセージをデキューする適用プロセスに、ポジティブ・ルール・セットまたはネガティブ・ルール・セットがない場合も、適用プロセスによって、キュー内のすべての永続LCRおよび 永続ユーザー・メッセージがデキューされます。

適用プロセスのパラメータの設定

適用プロセス・パラメータを設定するには、DBMS_APPLY_ADMパッケージのSET_PARAMETERプロシージャを使用します。適用プロセス・パラメータによって、適用プロセスの動作が制御されます。

たとえば、次のプロシージャでは、適用プロセスstrm01_applycommit_serializationパラメータがDEPENDENT_TRANSACTIONSに設定されます。commit_serializationパラメータをこの値に設定にすると、適用プロセスはトランザクションを任意の順序でコミットできます。

BEGIN
  DBMS_APPLY_ADM.SET_PARAMETER(
    apply_name   => 'strm01_apply',
    parameter    => 'commit_serialization',
    value        => 'DEPENDENT_TRANSACTIONS');
END;
/

注意:

  • valueパラメータは、パラメータ値が数値の場合にも、常にVARCHAR2値として入力されます。

  • valueパラメータがNULLに設定されているか、または指定されていない場合、パラメータはデフォルト値に設定されます。

  • parallelism適用プロセス・パラメータを1より大きい値に設定する場合は、適用プロセスで変更が適用される表のすべての一意キー列と外部キー列について、ソース・データベースに条件付きのサプリメンタル・ログ・グループを指定する必要があります。構成によっては、これらの表の他の列についても同様にサプリメンタル・ロギングが必要になる場合があります。



関連項目:

  • 「適用プロセス・パラメータ」

  • Oracle Enterprise Managerを使用した適用プロセス・パラメータの設定については、Oracle Database 2日でデータ・レプリケーションおよび統合ガイドを参照

  • 適用プロセス・パラメータの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』DBMS_APPLY_ADM.SET_PARAMETERプロシージャに関する項を参照

  • サプリメンタル・ロギングの指定の詳細は、『Oracle Streamsレプリケーション管理者ガイド』を参照


適用プロセスの適用ユーザーの設定

適用ユーザーは、適用プロセスルール・セットを満たすすべてのDML変更およびDDL変更を適用し、ユーザー定義の適用ハンドラを実行するユーザーです。適用プロセスの適用ユーザーを設定するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでapply_userパラメータを使用します。

適用ユーザーを変更するには、ALTER_APPLYプロシージャを起動するユーザーにDBAロールが付与されている必要があります。SYSユーザーのみが、SYSapply_userを設定できます。

たとえば、次のプロシージャでは、適用プロセスstrm03_applyの適用ユーザーがhrに設定されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name => 'strm03_apply',
    apply_user => 'hr');
END;
/

このプロシージャを実行すると、新しい適用ユーザーに、適用プロセスで使用されるキューのデキュー権限が付与され、そのユーザーがキューの保護キュー・ユーザーとして構成されます。また、適用ユーザーが次の権限を持っていることを確認する必要があります。

  • 適用オブジェクトに対してDML変更およびDDL変更を実行するための権限

  • 適用プロセスで使用するルール・セットのEXECUTE権限

  • ルール・セットで使用するすべてのカスタム・ルールベースの変換ファンクションのEXECUTE権限

  • すべての適用ハンドラ・プロシージャのEXECUTE権限

これらの権限は、適用ユーザーに直接付与するか、ロールを介して付与できます。

また、適用ユーザーには、適用プロセスで実行されるサブプログラムで起動されるすべてのパッケージ(Oracle提供パッケージを含む)に対するEXECUTE権限を付与する必要があります。これらの権限は、適用ユーザーに直接付与する必要があります。これらの権限は、ロールを介して付与することはできません。


注意:

Oracle Database Vaultがインストールされている場合は、「Oracle StreamsおよびOracle Data Vault」に記載されている手順に従って、適切な権限やロールが付与されていることを確認してください。

DMLハンドラの管理

DMLハンドラは、適用プロセスによってデキューされた行論理変更レコード(行LCR)を処理します。DMLハンドラには2つのタイプがあります。文DMLハンドラとプロシージャDMLハンドラです。文DMLハンドラは、SQL文のコレクションを使用して行LCRを処理します。一方プロシージャDMLハンドラは、PL/SQLプロシージャを使用して行LCRを処理します。

この項では、DMLハンドラの管理手順について説明します。

文DMLハンドラの管理

この項では、文DMLハンドラの次の管理手順について説明します。

文DMLハンドラの作成および適用プロセスへの追加

文DMLハンドラを作成して適用プロセスに追加するには、次の2とおりの方法があります。

  • 1つ目は、文DMLハンドラの作成、1つの文の追加および適用プロセスへのその文DMLハンドラの追加をすべて1ステップで行う方法です。

  • 2つ目は、文DMLハンドラの作成、1つ以上の文の追加および適用プロセスへのその文DMLハンドラの追加を個々のステップで行う方法です。

通常、文DMLハンドラに含まれる文が1つのみの場合には1ステップの方法が最適です。文DMLハンドラに複数の文が含まれる場合には複数ステップの方法が最適です。

次の各項では、それぞれの方法について詳しく説明する例を示します。

1つの文を含む文DMLハンドラの作成

一部のOracle Streamsレプリケーション環境では、レプリケートされた表はその表を共有するデータベースでまったく同じではありません。このような環境では、文DMLハンドラによって、行LCRで実行されたDML変更が変更される可能性があります。文DMLハンドラでは行LCRの列値は変更できません。ただし、文DMLハンドラでSQLを使用し、行を挿入したり、行LCRの列値とは異なる列値で行を更新できます。

この項の例では、次のことを想定しています。

  • Oracle Streamsレプリケーション環境は、ソース・データベースと宛先データベースとの間でoe.orders表に変更をレプリケートするように構成されています。oe.orders表への変更はソース・データベースで取得プロセスまたは同期取得によって取得され、伝播によって宛先データベースに送信されて、宛先データベースで適用プロセスによって適用されます。

  • ソース・データベースでは、oe.orders表にorder_status列が含まれます。宛先データベースで1order_statusの挿入が適用されると、order_status2に変更されることが想定されます。この例では、文DMLハンドラによってこの変更が行われます。1ではないorder_statusが挿入されると、文DMLハンドラでは、order_status値を変更せずに行LCRの元の変更が適用されます。

oe.orders表への挿入を変更する文DMLハンドラを作成するには、次の手順を実行します。

  1. この例のために、ソース・データベースで次のように必須のサプリメンタル・ロギングを指定します。

    1. ソース・データベースにOracle Streams管理者として接続します。

      SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

    2. oe.orders表のorder_status列を含む無条件サプリメンタル・ログ・グループを次のように指定します。

      ALTER TABLE oe.orders ADD SUPPLEMENTAL LOG GROUP log_group_ord_stat  (order_status) ALWAYS;
      

      宛先データベースで文DMLハンドラによって使用されるすべての列は、ソース・データベースで無条件ログ・グループに存在している必要があります。

  2. 宛先データベースにOracle Streams管理者として接続します。

  3. 文DMLハンドラを作成して適用プロセスに追加します。

    DECLARE
      stmt CLOB;
    BEGIN
      stmt := 'INSERT INTO oe.orders(
                 order_id,
                 order_date, 
                 order_mode,
                 customer_id,
                 order_status,
                 order_total,
                 sales_rep_id,
                 promotion_id) 
               VALUES(
                 :new.order_id,
                 :new.order_date, 
                 :new.order_mode,
                 :new.customer_id,
                 DECODE(:new.order_status, 1, 2, :new.order_status),
                 :new.order_total,
                 :new.sales_rep_id,
                 :new.promotion_id)';
      DBMS_APPLY_ADM.ADD_STMT_HANDLER(
        object_name        => 'oe.orders',
        operation_name     => 'INSERT',
        handler_name       => 'modify_orders',
        statement          => stmt,
        apply_name         => 'apply$_sta_2',
        comment            => 'Modifies inserts into the orders table');
    END;
    /
    

    DECODEファンクションによってorder_status1から2に変更されることに注意してください。行LCRのorder_status1でない場合、DECODEファンクションでデフォルトに:new.order_statusを指定することにより、DECODEファンクションでは元のorder_status値が使用されます。

    ADD_STMT_HANDLERプロシージャによって、modify_orders文DMLハンドラが作成されてapply$_sta_2適用プロセスに追加されます。文DMLハンドラは、oe.orders表への挿入を実行する行LCRがこの適用プロセスによってデキューされるときに起動されます。この表に対して行われる更新や削除を実行する行LCRを変更するには、個別の文DMLハンドラが必要となります。


注意:

  • modify_orders文DMLハンドラのこの文により、宛先の表に対する行変更が実行されます。したがって、文DMLハンドラに実行文を追加する必要はありません。この文によって実行される行変更は、適用プロセスによって行LCRのトランザクションに対するコミット・ディレクティブがデキューされるときにコミットされます。

  • この例では、ADD_STMT_HANDLERプロシージャによって文DMLハンドラがapply$_sta_2適用プロセスに追加されます。データベース内のすべての適用プロセスによって使用される汎用文DMLハンドラを追加するには、このプロシージャのapply_nameパラメータを省略するか、またはapply_nameパラメータをNULLに設定します。


1つ以上の文を含む文DMLハンドラの作成

文DMLハンドラを使用すると、表に対して行われた変更を追跡できます。この例では、文DMLハンドラによってhr.jobs表に対して行われた更新が追跡されます。

この項の例では、次のことを想定しています。

  • Oracle Streamsレプリケーション環境は、ソース・データベースと宛先データベースとの間でhr.jobs表に変更をレプリケートするように構成されています。hr.jobs表への変更はソース・データベースで取得プロセスまたは同期取得によって取得され、伝播によって宛先データベースに送信されて、宛先データベースで適用プロセスによって適用されます。hr.jobs表には、ある組織の様々な役職に対する最小および最大の給与が含まれます。

  • 給与情報に対する更新およびこれらの更新がいつ行われたかを追跡することが目的です。この目的のために、文DMLハンドラによってhr.track_jobs表に行が挿入されます。

  • hr.jobs表に変更をレプリケートするには、適用プロセスで行LCRを実行する必要もあります。

hr.jobsに対する更新を追跡する文DMLハンドラを作成するには、次の手順を実行します。

  1. ソース・データベースにOracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. hr.jobs表のすべての列を含む無条件サプリメンタル・ログ・グループを指定します。次に例を示します。

    ALTER TABLE hr.jobs ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
    

    宛先データベースで文DMLハンドラによって使用されるすべての列は、ソース・データベースで無条件ログ・グループに存在している必要があります。

  3. 宛先データベースにhrユーザーとして接続します。

  4. 追跡表の順序を次のように作成します。

    CREATE SEQUENCE hr.track_jobs_seq 
       START WITH 1
       INCREMENT BY 1;
    
  5. hr.jobs表に対する変更を追跡する表を次のように作成します。

    CREATE TABLE hr.track_jobs( 
       change_id       NUMBER  CONSTRAINT track_jobs_pk PRIMARY KEY,
       job_id          VARCHAR2(10), 
       job_title       VARCHAR2(35),
       min_salary_old  NUMBER(6),
       min_salary_new  NUMBER(6),
       max_salary_old  NUMBER(6),
       max_salary_new  NUMBER(6),
       timestamp       TIMESTAMP);
    

    文DMLハンドラは、手順4で作成した順序を使用して、追跡した変更ごとにhr.track_jobs表のchange_id列に一意の値を挿入します。

  6. 宛先データベースにOracle Streams管理者として接続します。

  7. 文DMLハンドラを次のように作成します。

    BEGIN
      DBMS_STREAMS_HANDLER_ADM.CREATE_STMT_HANDLER(
        handler_name => 'track_jobs',
        comment      => 'Tracks updates to the jobs table');
    END;
    /
    
  8. 行LCRを実行する文DMLハンドラに、次のように文を追加します。

    DECLARE
      stmt CLOB;
    BEGIN
      stmt := ':lcr.execute TRUE';
      DBMS_STREAMS_HANDLER_ADM.ADD_STMT_TO_HANDLER(
        handler_name       => 'track_jobs',
        statement          => stmt,
        execution_sequence => 10);
    END;
    /
    

    TRUE引数は、LCR$_ROW_RECORDタイプのEXECUTEメンバー・プロシージャのconflict_resolutionパラメータに対して使用されます。TRUE引数は、行LCRの実行時に、表に対して定義された任意の競合解決が使用されることを示します。行LCRの実行時に競合解決を使用しない場合は、FALSEを指定します。


    ヒント:

    表に対する変更を追跡するがレプリケートは行わない場合は、文DMLハンドラに実行文を含めません。


    関連項目:

    『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』

  9. 行LCRへの変更を追跡する文DMLハンドラに、次のように文を追加します。

    DECLARE
      stmt CLOB;
    BEGIN
      stmt := 'INSERT INTO hr.track_jobs(
                 change_id,
                 job_id, 
                 job_title,
                 min_salary_old,
                 min_salary_new,
                 max_salary_old,
                 max_salary_new,
                 timestamp) 
               VALUES(
                 hr.track_jobs_seq.NEXTVAL,
                 :new.job_id,
                 :new.job_title,
                 :old.min_salary,
                 :new.min_salary,
                 :old.max_salary,
                 :new.max_salary,
                 :source_time)';
      DBMS_STREAMS_HANDLER_ADM.ADD_STMT_TO_HANDLER(
        handler_name       => 'track_jobs',
        statement          => stmt,
        execution_sequence => 20);
    END;
    /
    

    この文により、hr.jobs表の行を更新する各行LCRに対して、hr.track_jobs表に行が挿入されます。hr.track_jobs表に挿入される値には、給与列ごとの古い値と新しい値を追跡するために行LCRの古い値と新しい値が使用されることに注意してください。また、行LCRのsource_time属性はtimestamp列を移入するために使用されます。

  10. 文DMLハンドラを適用プロセスに追加します。たとえば、次のプロシージャを使用すると、文DMLハンドラが適用プロセスapply$_sta_2に追加されます。

    BEGIN
      DBMS_APPLY_ADM.ADD_STMT_HANDLER(
        object_name    => 'hr.jobs',
        operation_name => 'UPDATE',
        handler_name   => 'track_jobs',
        apply_name     => 'apply$_sta_2');
    END;
    /
    

    注意:

    この例では、ADD_STMT_HANDLERプロシージャによって文DMLハンドラがapply$_sta_2適用プロセスに追加されます。データベース内のすべての適用プロセスによって使用される汎用文DMLハンドラを追加するには、このプロシージャのapply_nameパラメータを省略するか、またはapply_nameパラメータをNULLに設定します。

文DMLハンドラへの文の追加

文DMLハンドラに文を追加するには、DBMS_STREAMS_HANDLER_ADMパッケージのADD_STMT_TO_HANDLERプロシージャを実行して、文DMLハンドラに対してまだ指定されていない実行順序番号を指定します。

この項の例では、modify_orders文DMLハンドラに文を追加します。この文DMLハンドラは「1つの文を含む文DMLハンドラの作成」で作成したものです。この文により、oe.orders表への挿入が変更されます。

この項の例では、宛先データベースで特定の顧客に対して注文の10%を割引するとします。oe.orders表でのこの顧客のcustomer_id値は118です。この場合、文DMLハンドラのSQL文を使用して、customer_id値が118oe.orders表への挿入について、order_total値に.9を乗算します。

modify_orders文DMLハンドラに文を追加するには、次の手順を実行します。

  1. 適用プロセスが構成されている宛先データベースに、Oracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. 文DMLハンドラの文によってすでに使用されている実行順序番号を次のようにチェックします。

    COLUMN HANDLER_NAME HEADING 'Statement|Handler' FORMAT A15
    COLUMN EXECUTION_SEQUENCE HEADING 'Execution|Sequence' FORMAT 999999
    COLUMN STATEMENT HEADING 'Statement' FORMAT A50
    
    SET LONG  8000
    SET PAGES 8000
    SELECT HANDLER_NAME,
           EXECUTION_SEQUENCE,
           STATEMENT
      FROM DBA_STREAMS_STMTS
      WHERE HANDLER_NAME = 'MODIFY_ORDERS'
      ORDER BY EXECUTION_SEQUENCE;
    

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

    Statement       Execution
    Handler          Sequence Statement
    --------------- --------- --------------------------------------------------
    MODIFY_ORDERS           1 INSERT INTO oe.orders(
                                           order_id,
                                           order_date,
                                           order_mode,
                                           customer_id,
                                           order_status,
                                           order_total,
                                           sales_rep_id,
                                           promotion_id)
                                         VALUES(
                                           :new.order_id,
                                           :new.order_date,
                                           :new.order_mode,
                                           :new.customer_id,
                                           DECODE(:new.order_status, 1, 2, :new.
                              order_status),
                                           :new.order_total,
                                           :new.sales_rep_id,
                                           :new.promotion_id)
    

    この出力は、文DMLハンドラに含まれる文が1つのみであり、この1つの文の実行順序番号が1であることを示しています。

  3. 文DMLハンドラにすべての注文を10%割引する文を次のように追加します。

    DECLARE
      stmt CLOB;
    BEGIN
      stmt := 'UPDATE oe.orders SET order_total=order_total*.9
                 WHERE order_id=:new.order_id AND :new.customer_id=118';
      DBMS_STREAMS_HANDLER_ADM.ADD_STMT_TO_HANDLER(
        handler_name       => 'modify_orders',
        statement          => stmt,
        execution_sequence => 10);
    END;
    /
    

    この文により、実行順序番号が1の文によって挿入された行が更新されます。したがって、この文の実行順序番号は1より大きい値である必要があります。この例では、追加された文の実行順序番号に10を指定しています。


    ヒント:

    ADD_STMT_TO_HANDLERプロシージャでexecution_sequenceパラメータがNULLに設定されている場合、この文は、文DMLハンドラ内のどの文の実行順序番号よりも大きい実行順序番号で文DMLハンドラに追加されます。したがって、この例では、execution_sequenceパラメータを省略するか、またはNULLに設定できます。

これらの手順を完了した後、手順2の問合せに対する出力は次のようになります。

Statement       Execution
Handler          Sequence Statement
--------------- --------- --------------------------------------------------
MODIFY_ORDERS           1 INSERT INTO oe.orders(
                                       order_id,
                                       order_date,
                                       order_mode,
                                       customer_id,
                                       order_status,
                                       order_total,
                                       sales_rep_id,
                                       promotion_id)
                                     VALUES(
                                       :new.order_id,
                                       :new.order_date,
                                       :new.order_mode,
                                       :new.customer_id,
                                       DECODE(:new.order_status, 1, 2, :new.
                          order_status),
                                       :new.order_total,
                                       :new.sales_rep_id,
                                       :new.promotion_id)
 
MODIFY_ORDERS          10 UPDATE oe.orders SET order_total=order_total*.9
                                       WHERE order_id=:new.order_id AND :new.
                          customer_id=118

この出力は、実行順序番号が10の新しい文が文DMLハンドラに追加されていることを示しています。

文DMLハンドラ内の文の変更

文DMLハンドラ内の文を変更するには、DBMS_STREAMS_HANDLER_ADMパッケージのADD_STMT_TO_HANDLERプロシージャを実行し、変更する文の実行順序番号を指定します。

この項の例では、track_jobs文DMLハンドラの実行順序番号が20の文が変更されます。この文DMLハンドラは「1つ以上の文を含む文DMLハンドラの作成」で作成したものです。これにより、hr.track_jobs表を使用してhr.jobs表への変更が追跡されます。

この項の例では、hr.jobs表を更新したユーザーも追跡するとします。この場合、ソース・データベースで取得された行LCRにこの情報を追加して、user_name列をhr.track_jobs表に追加し、ユーザーを追跡するように文DMLハンドラ内の文を変更します。

文DMLハンドラ内の文を変更するには、次の手順を実行します。

  1. ソース・データベースにOracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. ソース・データベースで取得された行LCR情報に、次のようにユーザー名を追加します。

    BEGIN
      DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE(
        capture_name   => 'sta$cap',
        attribute_name => 'username',
        include        => TRUE);
    END;
    /
    

    capture_nameパラメータで、文DMLハンドラによって処理される変更を取得する取得プロセスまたは同期取得を指定します。

  3. 宛先データベースにOracle Streams管理者として接続します。

  4. user_name列をhr.track_jobs表に次のように追加します。

    ALTER TABLE hr.track_jobs
      ADD (user_name VARCHAR2(30));
    
  5. track_jobs文DMLハンドラの実行順序番号が20の文を次のように変更します。

    DECLARE
      stmt CLOB;
    BEGIN
      stmt := 'INSERT INTO hr.track_jobs(
                 change_id,
                 job_id, 
                 job_title,
                 min_salary_old,
                 min_salary_new,
                 max_salary_old,
                 max_salary_new,
                 timestamp,
                 user_name) 
               VALUES(
                 hr.track_jobs_seq.NEXTVAL,
                 :new.job_id,
                 :new.job_title,
                 :old.min_salary,
                 :new.min_salary,
                 :old.max_salary,
                 :new.max_salary,
                 :source_time,
                 :extra_attribute.username)';
      DBMS_STREAMS_HANDLER_ADM.ADD_STMT_TO_HANDLER(
        handler_name       => 'track_jobs',
        statement          => stmt,
        execution_sequence => 20);
    END;
    /
    

    変更した文により、行LCRのusername情報をhr.track_jobs表のuser_name列に挿入して、ユーザー追跡を追加します。usernameは追加のLCR属性であり、次の構文を使用して指定する必要があることに注意してください。

    :extra_attribute.username
    

文DMLハンドラからの文の削除

文DMLハンドラから文を削除するには、DBMS_STREAMS_HANDLER_ADMパッケージのREMOVE_STMT_FROM_HANDLERプロシージャを実行し、削除する文の実行順序番号を指定します。

この項の例では、track_jobs文DMLハンドラから実行順序番号が10の文が削除されます。この文DMLハンドラは「1つ以上の文を含む文DMLハンドラの作成」で作成したものです。これにより、hr.track_jobs表を使用してhr.jobs表への変更が追跡されます。

この項の例では、hr.jobs表に対する更新を含む行LCRの実行が不要になったことを想定しています。この場合、この行LCRを実行する文を削除する必要があり、track_jobs文DMLハンドラでのこの文の実行順序番号は10です。

文DMLハンドラから文を削除するには、次の手順を実行します。

  1. 文DMLハンドラを含むデータベースにOracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. 文DMLハンドラから、文を次のように削除します。

    BEGIN
      DBMS_STREAMS_HANDLER_ADM.REMOVE_STMT_FROM_HANDLER(
        handler_name       => 'track_jobs',
        execution_sequence => 10);
    END;
    /
    

適用プロセスからの文DMLハンドラの削除

適用プロセスから文DMLハンドラを削除するには、DBMS_APPLY_ADMパッケージのREMOVE_STMT_HANDLERプロシージャを実行します。

この項の例では、apply$_sta_2適用プロセスからtrack_jobs文DMLハンドラが削除されます。この文DMLハンドラは「1つ以上の文を含む文DMLハンドラの作成」で作成したものです。これにより、hr.track_jobs表を使用してhr.jobs表への変更が追跡されます。

適用プロセスから文DMLハンドラを削除するには、次の手順を実行します。

  1. 適用プロセスが使用されるデータベースにOracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. 適用プロセスから次のように文DMLハンドラを削除します。

    BEGIN
      DBMS_APPLY_ADM.REMOVE_STMT_HANDLER(
        object_name    => 'hr.jobs',
        operation_name => 'UPDATE',
        handler_name   => 'track_jobs',
        apply_name     => 'apply$_sta_2');
    END;
    /
    

文DMLハンドラは、適用プロセスから削除した後でもデータベースには存在します。

文DMLハンドラの削除

データベースから文DMLハンドラを削除するには、DBMS_STREAMS_HANDLER_ADMパッケージのDROP_STMT_HANDLERプロシージャを実行します。

この項の例では、track_jobs文DMLハンドラが削除されます。この文DMLハンドラは「1つ以上の文を含む文DMLハンドラの作成」で作成したものです。これにより、hr.track_jobs表を使用してhr.jobs表への変更が追跡されます。

文DMLハンドラを削除するには、次の手順を実行します。

  1. 文DMLハンドラを含むデータベースにOracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. 文DMLハンドラを次のように削除します。

    exec DBMS_STREAMS_HANDLER_ADM.DROP_STMT_HANDLER('track_jobs');
    

プロシージャDMLハンドラの管理

この項では、プロシージャDMLハンドラの次の管理手順について説明します。

プロシージャDMLハンドラの作成

プロシージャDMLハンドラには、次のシグネチャが必要です。

PROCEDURE user_procedure (
   parameter_name   IN  ANYDATA);

ここで、user_procedureはプロシージャの名前、parameter_nameはプロシージャに渡されるパラメータの名前です。プロシージャに渡されるパラメータは、行論理変更レコード(行LCR)をANYDATAにカプセル化したものです。

ユーザー・プロシージャには次の制限事項が適用されます。

  • COMMIT文またはROLLBACK文を実行しないでください。実行すると、行LCRを含むトランザクションの一貫性が失われる危険性があります。

  • 行LCR用のEXECUTEメンバー・プロシージャを使用して行を操作している場合は、1つの行操作で複数の行を操作しないでください。複数行を操作する任意のDML文を手動で作成して実行する必要があります。

  • コマンド・タイプがUPDATEまたはDELETEの場合、LCRに対してEXECUTEメンバー・プロシージャを使用して再実行される行操作では、以前の値リストにキー全体が含まれている必要があります。キーは、代替キーがSET_KEY_COLUMNSプロシージャによって指定されていないかぎり、少なくとも1つのNOT NULL列を含む主キーまたは最小の一意キーとなります。キーが指定されていない場合、キーはすべての表の列で構成されますが、LOB、LONGLONG RAWの各データ型、ユーザー定義型(オブジェクト型、REF、VARRAY、ネストした表など)およびOracle提供の型(Any型、XML型、空間型、メディア型など)の列は除外されます。

  • コマンド・タイプがINSERTの場合、LCR用のEXECUTEメンバー・プロシージャを使用して再発行された行操作には、新しい値のリストのキー全体が含まれる必要があります。含まれないと重複行が生じる可能性があります。キーは、代替キーがSET_KEY_COLUMNSプロシージャによって指定されていないかぎり、少なくとも1つのNOT NULL列を含む主キーまたは最小の一意キーとなります。キーが指定されていない場合、キーは非LOB、非LONGおよび非LONG RAW列のすべてで構成されます。

プロシージャDMLハンドラは、行LCRの任意のカスタム処理に使用できます。たとえば、ハンドラでLCRを変更してから、そのLCRに対するEXECUTEメンバー・プロシージャを使用してLCRを実行することができます。プロシージャDMLハンドラで行LCRを実行すると、適用プロセスはプロシージャDMLハンドラを再度呼び出すことなくLCRを適用します。

プロシージャDMLハンドラでSQL生成を使用して、表に対して行われるDML変更を記録することもできます。これらの変更は、表かファイルに記録できます。たとえば、この項のサンプル・プロシージャDMLハンドラでは、SQL生成を使用し、GET_ROW_TEXTメンバー・プロシージャによりhr.departments表に対して実行された各UPDATE SQL文を記録します。プロシージャDMLハンドラによって、EXECUTEメンバー・プロシージャを使用して行LCRも適用されます。

このプロシージャDMLハンドラで使用されるプロシージャを作成するには、次の手順を実行します。

  1. SQL*Plusで、データベースにOracle Streams管理者として接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. テキスト・ファイルが含まれるディレクトリに対してディレクトリ・オブジェクトを作成します。

    この例では、hr.departments表に対して実行されたUPDATE SQL文が、適用プロセスによってこのディレクトリのテキスト・ファイルに書き込まれます。

    たとえば、/usr/sql_genディレクトリに対してSQL_GEN_DIRというディレクトリ・オブジェクトを作成するには、次のSQL文を入力します。

    CREATE DIRECTORY SQL_GEN_DIR AS '/usr/sql_gen';
    
  3. SQL文が書き込まれるテキスト・ファイルが、手順2で指定したディレクトリに存在することを確認します。

    この例では、sql_gen_file.txtファイルがファイル・システムの/usr/sql_genディレクトリに存在することを確認します。

  4. プロシージャDMLハンドラに対して、次のようにプロシージャを作成します。

    CREATE OR REPLACE PROCEDURE strmadmin.sql_gen_dep(lcr_anydata IN SYS.ANYDATA) IS
      lcr          SYS.LCR$_ROW_RECORD;
      int          PLS_INTEGER;
      row_txt_clob CLOB;
      fp           UTL_FILE.FILE_TYPE;
    BEGIN
      int   := lcr_anydata.GETOBJECT(lcr);
      DBMS_LOB.CREATETEMPORARY(row_txt_clob, TRUE);
      -- Generate SQL from row LCR and save to file
      lcr.GET_ROW_TEXT(row_txt_clob);
      fp := UTL_FILE.FOPEN (
         location     => 'SQL_GEN_DIR',
         filename     => 'sql_gen_file.txt',
         open_mode    => 'a',
         max_linesize => 5000);
      UTL_FILE.PUT_LINE(
         file      => fp,
         buffer    => row_txt_clob,
         autoflush => TRUE);
      DBMS_LOB.TRIM(row_txt_clob, 0);
      UTL_FILE.FCLOSE(fp); 
      --  Apply row LCR
      lcr.EXECUTE(TRUE);
    END;
    /
    

プロシージャを作成した後、「プロシージャDMLハンドラの設定」の手順に従って、作成したプロシージャをプロシージャDMLハンドラとして設定できます。


注意:

  • 宛先データベースでプロシージャDMLハンドラが必要とする任意の列に対して、ソース・データベースで無条件サプリメンタル・ログ・グループを指定する必要があります。このサンプル・プロシージャDMLハンドラではSQL文が記録され、その他の方法で行LCRが操作されることはないため、このサンプル・プロシージャDMLハンドラに追加のサプリメンタル・ロギングは必要ありません。

  • プロシージャDMLハンドラを使用前にテストしたり、プロシージャDMLハンドラをデバッグするために、行LCRを作成し、適用プロセスのコンテキスト外でプロシージャDMLハンドラのプロシージャを実行できます。



関連項目:


プロシージャDMLハンドラの設定

プロシージャDMLハンドラにより、特定の表に対する特定の操作を含む任意の適用プロセスによってデキューされた各行LCRが処理されます。表に対する様々な操作を処理するために、同じ表で複数のプロシージャDMLハンドラを指定できます。ローカル・データベース内の指定した表に変更を適用するすべての適用プロセスでは、指定したプロシージャDMLハンドラが使用されます。

DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを使用して、プロシージャDMLハンドラを設定します。たとえば、次のプロシージャでは、hr.departments表に対するUPDATE操作用のプロシージャDMLハンドラを設定します。したがって、変更をローカルに適用する任意の適用プロセスがhr.departments表に対するUPDATE操作を含む行LCRをデキューすると、適用プロセスは行LCRをstrmadminスキーマのsql_gen_dep PL/SQLプロシージャに処理用に送信します。適用プロセスでは、このような変更を含む行LCRを直接適用することはありません。

この例では、apply_nameパラメータがNULLに設定されています。したがって、プロシージャDMLハンドラは、データベース内のすべての適用プロセスによって使用される汎用プロシージャDMLハンドラです。

BEGIN
  DBMS_APPLY_ADM.SET_DML_HANDLER(
    object_name         => 'hr.departments',
    object_type         => 'TABLE',
    operation_name      => 'UPDATE',
    error_handler       => FALSE,
    user_procedure      => 'strmadmin.sql_gen_dep',
    apply_database_link => NULL,
    apply_name          => NULL);
END;
/

注意:

  • プロシージャDMLハンドラを1つの適用プロセスに対してのみ指定するには、適用プロセスの名前をapply_nameパラメータで指定します。

  • 適用プロセスによってOracle以外のリモート・データベースに変更が適用される場合、この適用プロセスでは、同じ表に対して別のプロシージャDMLハンドラを使用できます。DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを実行して、apply_database_linkパラメータをNULL以外の値に設定することにより、Oracle以外のリモート・データベースに適用される変更に対してプロシージャDMLハンドラを指定できます。

  • operation_nameパラメータにDEFAULTを指定して、プロシージャをデータベース・オブジェクトのデフォルトのプロシージャDMLハンドラとして設定できます。この場合、データベース・オブジェクトに対する操作に別のプロシージャDMLハンドラが明確に設定されているのでなければ、データベース・オブジェクトに対するINSERTUPDATEDELETEおよびLOB_WRITEのすべてにこのプロシージャDMLハンドラが使用されます。



関連項目:

『Oracle Streamsレプリケーション管理者ガイド』

プロシージャDMLハンドラの設定解除

プロシージャDMLハンドラの設定を解除するには、DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを使用します。このプロシージャを実行するときに、特定の表に対する特定の操作について、user_procedureパラメータをNULLに設定します。プロシージャDMLハンドラの設定を解除した後、変更をローカルに適用する任意の適用プロセスで、このような変更を含む行LCRが直接適用されるようになります。

たとえば、次のプロシージャでは、hr.departments表に対するUPDATE操作について、プロシージャDMLハンドラの設定が解除されます。

BEGIN
  DBMS_APPLY_ADM.SET_DML_HANDLER(
    object_name    => 'hr.departments',
    object_type    => 'TABLE',
    operation_name => 'UPDATE',
    error_handler  => FALSE,
    user_procedure => NULL,
    apply_name     => NULL);
END;
/

DDLハンドラの管理

この項では、適用プロセスのDDLハンドラの作成、指定および削除の手順について説明します。


注意:

すべての適用済DDL LCRは、自動的にコミットされます。したがって、DDLハンドラがDDL LCRのEXECUTEメンバー・プロシージャをコールすると、自動的にコミットが実行されます。


関連項目:


適用プロセスのDDLハンドラの作成

DDLハンドラには、次のシグネチャが必要です。

PROCEDURE handler_procedure (
   parameter_name   IN  ANYDATA);

ここで、handler_procedureはプロシージャの名前、parameter_nameはプロシージャに渡されるパラメータの名前です。プロシージャに渡されるパラメータは、DDL LCRをANYDATAにカプセル化したものです。

DDLハンドラは、DDL LCRの任意のカスタム処理に使用できます。たとえば、ハンドラでLCRを変更してから、そのLCRに対するEXECUTEメンバー・プロシージャを使用してLCRを実行できます。DDLハンドラでDDL LCRを実行すると、適用プロセスはDDLハンドラを再度呼び出すことなくLCRを適用します。

また、DDLハンドラを使用してDDL変更の履歴を記録することもできます。たとえば、DDLハンドラを使用すると、DDLハンドラで処理したLCRに関する情報を表に挿入してから、EXECUTEメンバー・プロシージャを使用してLCRを適用できます。

このようなDDLハンドラを作成するには、最初に、履歴情報を保持するための表を次のように作成します。

CREATE TABLE strmadmin.history_ddl_lcrs(
  timestamp             DATE,
  source_database_name  VARCHAR2(128),
  command_type          VARCHAR2(30),
  object_owner          VARCHAR2(32),
  object_name           VARCHAR2(32),
  object_type           VARCHAR2(18),
  ddl_text              CLOB,
  logon_user            VARCHAR2(32),
  current_schema        VARCHAR2(32),
  base_table_owner      VARCHAR2(32),
  base_table_name       VARCHAR2(32),
  tag                   RAW(10),
  transaction_id        VARCHAR2(10),
  scn                   NUMBER);
CREATE OR REPLACE PROCEDURE history_ddl(in_any IN ANYDATA)  
 IS
   lcr       SYS.LCR$_DDL_RECORD;
   rc        PLS_INTEGER;
   ddl_text  CLOB;
 BEGIN
   -- Access the LCR
   rc := in_any.GETOBJECT(lcr);
   DBMS_LOB.CREATETEMPORARY(ddl_text, TRUE);
   lcr.GET_DDL_TEXT(ddl_text);
   --  Insert DDL LCR information into history_ddl_lcrs table
   INSERT INTO strmadmin.history_ddl_lcrs VALUES( 
     SYSDATE, lcr.GET_SOURCE_DATABASE_NAME(), lcr.GET_COMMAND_TYPE(), 
     lcr.GET_OBJECT_OWNER(), lcr.GET_OBJECT_NAME(), lcr.GET_OBJECT_TYPE(), 
     ddl_text, lcr.GET_LOGON_USER(), lcr.GET_CURRENT_SCHEMA(), 
     lcr.GET_BASE_TABLE_OWNER(), lcr.GET_BASE_TABLE_NAME(), lcr.GET_TAG(), 
     lcr.GET_TRANSACTION_ID(), lcr.GET_SCN());
   --  Apply DDL LCR
   lcr.EXECUTE();
   -- Free temporary LOB space
   DBMS_LOB.FREETEMPORARY(ddl_text);
END;
/

適用プロセスのDDLハンドラの設定

DDLハンドラによって、適用プロセスでデキューされたすべてのDDL LCRが処理されます。適用プロセスのDDLハンドラを設定するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでddl_handlerパラメータを使用します。たとえば、次のプロシージャでは、適用プロセスstrep01_applyのDDLハンドラがstrmadminスキーマ内のhistory_ddlプロシージャに設定されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name  => 'strep01_apply',
    ddl_handler => 'strmadmin.history_ddl');
END;
/

適用プロセスのDDLハンドラの削除

DDLハンドラによって、適用プロセスでデキューされたすべてのDDL LCRが処理されます。適用プロセスのDDLハンドラを削除するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでremove_ddl_handlerパラメータをTRUEに設定します。たとえば、次のプロシージャでは、適用プロセスstrep01_applyからDDLハンドラが削除されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name         => 'strep01_apply',
    remove_ddl_handler => TRUE);
END;
/

適用プロセスのメッセージ・ハンドラの管理

メッセージ・ハンドラは、永続ユーザー・メッセージを処理する適用ハンドラです。次の各項では、適用プロセスにメッセージ・ハンドラを設定または設定解除する手順について説明します。


関連項目:


適用プロセスのメッセージ・ハンドラの設定

適用プロセスメッセージ・ハンドラを設定するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでmessage_handlerパラメータを使用します。たとえば、次のプロシージャでは、適用プロセスstrm03_applyのメッセージ・ハンドラがoeスキーマ内のmes_handlerプロシージャに設定されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name      => 'strm03_apply',
    message_handler => 'oe.mes_handler');
END;
/

ALTER_APPLYプロシージャを実行するユーザーは、指定したメッセージ・ハンドラのEXECUTE権限を持っている必要があります。メッセージ・ハンドラが適用プロセスにすでに設定されている場合は、ALTER_APPLYプロシージャを実行して、適用プロセスのメッセージ・ハンドラを変更できます。

適用プロセスのメッセージ・ハンドラの設定解除

適用プロセスメッセージ・ハンドラを設定解除するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでremove_message_handlerパラメータをTRUEに設定します。たとえば、次のプロシージャでは、適用プロセスstrm03_applyのメッセージ・ハンドラの設定が解除されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name             => 'strm03_apply',
    remove_message_handler => TRUE);
END;
/

適用プロセスのプリコミット・ハンドラの管理

プリコミット・ハンドラは、トランザクションのコミット情報を受信し、カスタマイズした方法でコミット情報を処理できる適用ハンドラです。

次の各項では、適用プロセスのプリコミット・ハンドラの作成、設定および設定解除の手順について説明します。

適用プロセスのプリコミット・ハンドラの作成

プリコミット・ハンドラには、次のシグネチャが必要です。

PROCEDURE handler_procedure (
   parameter_name   IN  NUMBER);

ここで、handler_procedureはプロシージャの名前、parameter_nameはプロシージャに渡されるパラメータの名前です。プロシージャに渡されるパラメータは、適用プロセスで使用されるキューに含まれる内部コミット・ディレクティブのコミットSCNです。

プリコミット・ハンドラを使用すると、適用プロセスによって処理されたコミットの情報を記録できます。適用プロセスでは、取得LCR永続LCRまたは永続ユーザー・メッセージを適用できます。取得された行LCRの場合は、コミット・ディレクティブに、ソース・データベースからのトランザクションのコミットSCNが含まれます。永続LCRおよび永続ユーザー・メッセージの場合、コミットSCNは適用プロセスによって生成されます。

プリコミット・ハンドラ・プロシージャは、次の制限に従う必要があります。

  • コミットする作業は、自律型トランザクションである必要があります。

  • プロシージャで作成された指定のセーブ・ポイントまでロールバックする必要があります。

プリコミット・ハンドラで例外が発生した場合、適用トランザクション全体がロールバックされ、トランザクション内のすべてのメッセージがエラー・キューに移動されます。

たとえば、プリコミット・ハンドラは、適用プロセスによって適用された行LCRの監査に使用できます。このようなプリコミット・ハンドラを1つ以上の個別のプロシージャDMLハンドラとともに使用し、トランザクションのソース・データベースのコミットSCNを監査表に記録し、適用プロセスがトランザクションを適用する時間を監査表に記録する場合もあります。

特に、この例では、次の表の行LCRに関する情報を記録するプロシージャDMLハンドラとともに使用されるプリコミット・ハンドラが作成されます。

CREATE TABLE strmadmin.history_row_lcrs(
  timestamp             DATE,
  source_database_name  VARCHAR2(128),
  command_type          VARCHAR2(30),
  object_owner          VARCHAR2(32),
  object_name           VARCHAR2(32),
  tag                   RAW(10),
  transaction_id        VARCHAR2(10),
  scn                   NUMBER,
  commit_scn            NUMBER,
  old_values            SYS.LCR$_ROW_LIST,
  new_values            SYS.LCR$_ROW_LIST)
    NESTED TABLE old_values STORE AS old_values_ntab
    NESTED TABLE new_values STORE AS new_values_ntab;

プロシージャDMLハンドラは、適用プロセスによって処理される行LCRごとに、strmadmin.history_row_lcrs表に1行挿入します。この例で作成されるプリコミット・ハンドラは、トランザクションのコミット時に、strmadmin.history_row_lcrs表に1行挿入します。

history_row_lcrs表にコミット情報を挿入するプロシージャを作成します。

CREATE OR REPLACE PROCEDURE strmadmin.history_commit(commit_number IN NUMBER)  
 IS
 BEGIN
  -- Insert commit information into the history_row_lcrs table
  INSERT INTO strmadmin.history_row_lcrs (timestamp, commit_scn) 
    VALUES (SYSDATE, commit_number);
END;
/

適用プロセスのプリコミット・ハンドラの設定

プリコミット・ハンドラは、適用プロセスによってデキューされたすべてのコミット・ディレクティブを処理します。適用プロセスにプリコミット・ハンドラを設定すると、適用プロセスがデキューするすべてのコミット・ディレクティブの処理に使用されます。適用プロセスには1つのプリコミット・ハンドラのみを設定できます。

適用プロセスのプリコミット・ハンドラを設定するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでprecommit_handlerパラメータを使用します。たとえば、次のプロシージャでは、適用プロセスstrm01_applyのプリコミット・ハンドラにstrmadminスキーマのhistory_commitプロシージャが設定されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name        => 'strm01_apply',
    precommit_handler => 'strmadmin.history_commit');
END;
/

また、DBMS_APPLY_ADMパッケージのCREATE_APPLYプロシージャを使用して適用プロセスを作成する際に、プリコミット・ハンドラを指定することもできます。適用プロセスにプリコミット・ハンドラがすでに設定されている場合は、ALTER_APPLYプロシージャを実行して、適用プロセスのプリコミット・ハンドラを変更できます。

適用プロセスのプリコミット・ハンドラの設定解除

適用プロセスプリコミット・ハンドラを設定解除するには、DBMS_APPLY_ADMパッケージのALTER_APPLYプロシージャでremove_precommit_handlerパラメータをTRUEに設定します。たとえば、次のプロシージャでは、適用プロセスstrm01_applyのプリコミット・ハンドラの設定が解除されます。

BEGIN
  DBMS_APPLY_ADM.ALTER_APPLY(
    apply_name               => 'strm01_apply',
    remove_precommit_handler => TRUE);
END;
/

適用プロセスによるメッセージのエンキューの指定

この項では、ポジティブ・ルール・セットに指定したルールを使用する適用プロセスで、ルールを満たすメッセージがエンキューされる宛先キューを設定する手順について説明します。また、宛先キューの設定を削除する手順についても説明します。

ルールを満たすメッセージの宛先キューの設定

特定のルールを満たすメッセージの宛先キューを設定するには、DBMS_APPLY_ADMパッケージのSET_ENQUEUE_DESTINATIONプロシージャを使用します。たとえば、ルールemployees5の宛先キューをキューhr.change_queueに設定するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_ENQUEUE_DESTINATION(
    rule_name               =>  'employees5',
    destination_queue_name  =>  'hr.change_queue');
END;
/

このプロシージャでは、ルールのアクション・コンテキストを変更してキューを指定します。ポジティブ・ルール・セットemployees5ルールが含まれるローカル・データベースのすべての適用プロセスで、employees5ルールを満たすメッセージがhr.change_queueにエンキューされます。employees5ルールの宛先キューを変更するには、SET_ENQUEUE_DESTINATIONプロシージャを再実行して異なるキューを指定します。

指定したルールを使用する各適用プロセスの適用ユーザーは、指定したキューにメッセージをエンキューするために必要な権限を持っている必要があります。キューが保護キューの場合、適用ユーザーはキューの保護キュー・ユーザーである必要があります。

SET_ENQUEUE_DESTINATIONプロシージャを使用してエンキューされたメッセージは、手動でエンキューされている他のすべてのメッセージと同様です。このメッセージに対して、手動でのデキュー、apply_capturedパラメータをFALSEに設定して作成された適用プロセスによる適用、または他のキューへの伝播を実行できます。


注意:

  • 指定したルールは、適用プロセスのポジティブ・ルール・セットに含まれている必要があります。ルールが適用プロセスのネガティブ・ルール・セットに含まれている場合、適用プロセスはメッセージを宛先キューにエンキューしません。

  • 適用プロセスは、常にメッセージを永続キューにエンキューします。バッファ・キューへのメッセージのエンキューはできません。



関連項目:


ルールの宛先キュー設定の削除

指定したルールを満たすメッセージの宛先キューを削除するには、DBMS_APPLY_ADMパッケージのSET_ENQUEUE_DESTINATIONプロシージャを使用します。具体的には、このプロシージャで、ルールのdestination_queue_nameパラメータをNULLに設定します。ルールの宛先キューの指定が削除された場合、ルールを満たすメッセージは、適用プロセスによってキューにエンキューされません。

たとえば、ルールemployees5の宛先キューを削除するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_ENQUEUE_DESTINATION(
    rule_name               =>  'employees5',
    destination_queue_name  =>  NULL);
END;
/

ポジティブ・ルール・セットemployees5ルールが含まれるローカル・データベースのすべての適用プロセスで、employees5ルールを満たすメッセージがhr.change_queueにエンキューされなくなります。

適用プロセスの実行ディレクティブの指定

この項では、適用プロセスで、ポジティブ・ルール・セットで指定されたルールを満たすメッセージ用の実行ディレクティブを設定する手順について説明します。

ルールを満たすメッセージの実行の回避の指定

適用プロセスが、指定されたルールを満たすメッセージを実行しないように指定するには、DBMS_APPLY_ADMパッケージのSET_EXECUTEプロシージャを使用します。具体的には、このプロシージャで、ルールのexecuteパラメータをFALSEに設定します。ルールの実行ディレクティブをFALSEに設定すると、そのルールがポジティブ・ルール・セットに含まれる適用プロセスでは、そのルールを満たすメッセージは実行されません。

たとえば、適用プロセスでルールdepartments8を満たすメッセージが実行されないように指定するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_EXECUTE(
    rule_name   =>  'departments8',
    execute     =>  FALSE);
END;
/

このプロシージャは、ルールのアクション・コンテキストを変更して、実行ディレクティブを指定します。ポジティブ・ルール・セットにdepartments8ルールが含まれるローカル・データベースのすべての適用プロセスで、departments8ルールを満たすメッセージは実行されません。したがって、メッセージがLCRの場合、適用プロセスでは、LCRの変更が、関連するデータベース・オブジェクトに対して適用されません。また、適用プロセスでは、このルールを満たすメッセージは適用ハンドラに送信されません。


注意:

  • 適用プロセスが実行ディレクティブに従うには、指定したルールが適用プロセスのポジティブ・ルール・セットに含まれている必要があります。ルールが適用プロセスのネガティブ・ルール・セットに含まれている場合、適用プロセスはルールの実行ディレクティブを無視します。

  • 特定のルールを満たすメッセージを、実行せずに宛先キューにエンキューするには、SET_EXECUTEプロシージャとSET_ENQUEUE_DESTINATIONプロシージャを併用できます。SET_ENQUEUE_DESTINATIONプロシージャを使用してメッセージをエンキューすると、そのメッセージは手動でエンキューしたメッセージと同様になります。したがって、そのメッセージに対して、手動のデキュー、適用プロセスによる適用、または他のキューへの伝播を実行できます。



関連項目:


ルールを満たすメッセージの実行の指定

適用プロセスが、指定されたルールを満たすメッセージを実行するように指定するには、DBMS_APPLY_ADMパッケージのSET_EXECUTEプロシージャを使用します。具体的には、このプロシージャでルールのexecuteパラメータをTRUEに設定します。デフォルトでは、メッセージが適用プロセスのネガティブ・ルール・セットのルールを満たしていないことを想定して、適用プロセスのポジティブ・ルール・セットに含まれるルールを満たすメッセージが各適用プロセスで実行されます。したがって、ルールのexecuteパラメータが以前FALSEに設定されていた場合にのみ、TRUEに設定する必要があります。

たとえば、適用プロセスがルールdepartments8を満たすメッセージを実行するように指定するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_EXECUTE(
    rule_name   =>  'departments8',
    execute     =>  TRUE);
END;
/

ポジティブ・ルール・セットにdepartments8ルールが含まれるローカル・データベースのすべての適用プロセスで、departments8ルールを満たすメッセージが実行されます。したがって、メッセージがLCRの場合、適用プロセスによって、LCRの変更が、関連するデータベース・オブジェクトに対して適用されます。また、適用プロセスでは、このルールを満たすメッセージは適用ハンドラに送信されます(適用プロセスをそのように設定している場合)。

エラー・ハンドラの管理

エラー・ハンドラは、任意の適用プロセスによってデキューされた、指定の表に対する指定の操作を含む行LCRから生成されたエラーを処理します。

次の各項では、エラー・ハンドラの作成、設定および設定解除の手順について説明します。

エラー・ハンドラの作成

エラー・ハンドラを作成するには、DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを実行して、error_handlerパラメータをTRUEに設定します。

エラー・ハンドラには、次のシグネチャが必要です。

PROCEDURE user_procedure (
     message             IN ANYDATA,
     error_stack_depth   IN NUMBER,
     error_numbers       IN DBMS_UTILITY.NUMBER_ARRAY,
     error_messages      IN emsg_array);

user_procedureは、プロシージャ名です。各パラメータは必須であり、指定されたデータ型を使用する必要があります。ただし、パラメータ名は変更できます。emsg_arrayパラメータには、VARCHAR2型のPL/SQL表である76文字以上のユーザー定義配列で指定する必要があります。


注意:

エラー・ハンドラは、SET_DML_HANDLERで指定されたユーザー・プロシージャに関するいくつかの条件を満たす必要があります。これらの条件の詳細は、「DMLハンドラの管理」を参照してください。

エラー・ハンドラの実行結果は、次のいずれかになります。

  • エラー・ハンドラによって、エラーが正常に解決され、該当する場合は行LCRが適用され、制御が適用プロセスに戻されます。

  • エラー・ハンドラがエラーの解決に失敗し、エラーが発生します。エラーが発生すると、トランザクションはロールバックされ、エラー・キューに置かれます。

DML操作を再実行する場合は、エラー・ハンドラ・プロシージャで、LCR用のEXECUTEメンバー・プロシージャを実行します。

次の例では、hr.regions表の主キー違反を解決するエラー・ハンドラregions_pk_errorを作成します。宛先データベースでは、ユーザーがhr.regions表に行を挿入し、リモート・ソース・データベース取得プロセスによって発生したhr.regions表に対する変更が、適用プロセスによって適用されるとします。この環境では、宛先データベースのユーザーが、ソース・データベースから適用された挿入行LCRと同じ主キー値を持つ行を挿入すると、エラーが発生する可能性があります。

この例では、hr.regions表の主キー違反によるエラーごとに次の情報を記録するため、strmadminスキーマにerrorlogという表を作成します。

  • エラー発生時のタイム・スタンプ

  • エラーが発生した適用プロセスの名前

  • エラーの原因となったユーザー(送信者)。これは、取得LCRの場合は取得プロセス名、同期取得によって取得された永続LCRの場合は同期取得名、アプリケーションによってエンキューされた永続LCRおよび永続ユーザー・メッセージの場合はOracle Streams Advanced Queuing(AQ)エージェントの名前です

  • 将来、他のオブジェクトのエラーがログに記録される可能性があるため、DMLの操作が実行されたオブジェクトの名前

  • DML操作で使用されたコマンドのタイプ

  • 違反となった制約の名前

  • エラー・メッセージ

  • エラーの原因となったLCR

このエラー・ハンドラでは、hr.regions表での主キー違反によるエラーのみが解決されます。このタイプのエラーを解決するために、エラー・ハンドラでは、順序を使用して行LCRのregion_id値が変更した後、行LCRを実行して適用します。他のタイプのエラーが発生した場合は、errorlog表に格納した行LCRを使用して手動でエラーを解決できます。

たとえば、エラー・ハンドラでは次のエラーが解決されます。

  1. 宛先データベースで、ユーザーがhr.regions表にregion_idの値が6region_nameの値が'LILLIPUT'の1行を挿入します。

  2. ソース・データベースで、ユーザーがhr.regions表にregion_idの値が6region_nameの値が'BROBDINGNAG'の1行を挿入します。

  3. ソース・データベースの取得プロセスが、手順2で説明した変更を取得します。

  4. 伝播によって、ソース・データベースのキューから宛先データベースの適用プロセスで使用されるキューに、変更を含むLCRが伝播されます。

  5. 適用プロセスがLCRを適用すると、主キー違反のためにエラーが発生します。

  6. 適用プロセスがエラー・ハンドラを起動して、エラーを処理します。

  7. エラー・ハンドラは、エラーをstrmadmin.errorlog表に記録します。

  8. エラー・ハンドラは、順序を使用してLCR内でregion_id値を変更し、そのLCRを実行して適用します。

regions_pk_errorエラー・ハンドラを作成する手順は、次のとおりです。

  1. SQL*Plusで、データベースにhrユーザーとして接続します。

    SQL*Plusでデータベースに接続する方法については、『Oracle Database管理者ガイド』を参照してください。

  2. 新しい主キー値に割り当てるためにエラー・ハンドラで使用される順序を作成します。

    CREATE SEQUENCE hr.reg_exception_s START WITH 9000;
    

    この例では、宛先データベースのユーザーはregion_id8999を超える行をhr.regions表に挿入しないと仮定します。

  3. Oracle Streams管理者に、順序に対するALL権限を付与します。

    GRANT ALL ON reg_exception_s TO strmadmin;
    
  4. データベースにOracle Streams管理者として接続します。

  5. errorlog表を作成します。

    CREATE TABLE strmadmin.errorlog(
      logdate       DATE,
      apply_name    VARCHAR2(30),
      sender        VARCHAR2(100),
      object_name   VARCHAR2(32),
      command_type  VARCHAR2(30),
      errnum        NUMBER,
      errmsg        VARCHAR2(2000),
      text          VARCHAR2(2000),
      lcr           SYS.LCR$_ROW_RECORD);
    
  6. regions_pk_errorプロシージャを含めるパッケージを作成します。

    CREATE OR REPLACE PACKAGE errors_pkg 
    AS
     TYPE emsg_array IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;
     PROCEDURE regions_pk_error( 
       message            IN ANYDATA,
       error_stack_depth  IN NUMBER,
       error_numbers      IN DBMS_UTILITY.NUMBER_ARRAY,
       error_messages     IN EMSG_ARRAY);
    END errors_pkg ;
    /
    
  7. パッケージ本体を作成します。

    CREATE OR REPLACE PACKAGE BODY errors_pkg AS
     PROCEDURE regions_pk_error ( 
       message            IN ANYDATA,
       error_stack_depth  IN NUMBER,
       error_numbers      IN DBMS_UTILITY.NUMBER_ARRAY,
       error_messages     IN EMSG_ARRAY )
     IS
      reg_id     NUMBER;
      ad         ANYDATA;
      lcr        SYS.LCR$_ROW_RECORD;
      ret        PLS_INTEGER;
      vc         VARCHAR2(30);
      apply_name VARCHAR2(30);
      errlog_rec errorlog%ROWTYPE ;
      ov2        SYS.LCR$_ROW_LIST;
     BEGIN
      -- Access the error number from the top of the stack.
      -- In case of check constraint violation,
      -- get the name of the constraint violated.
      IF error_numbers(1) IN ( 1 , 2290 ) THEN
       ad  := DBMS_STREAMS.GET_INFORMATION('CONSTRAINT_NAME');
       ret := ad.GetVarchar2(errlog_rec.text);
      ELSE 
       errlog_rec.text := NULL ;
      END IF ;
      -- Get the name of the sender and the name of the apply process.
      ad  := DBMS_STREAMS.GET_INFORMATION('SENDER');
      ret := ad.GETVARCHAR2(errlog_rec.sender);
      apply_name := DBMS_STREAMS.GET_STREAMS_NAME();
      -- Try to access the LCR.
      ret := message.GETOBJECT(lcr);
      errlog_rec.object_name  := lcr.GET_OBJECT_NAME() ;
      errlog_rec.command_type := lcr.GET_COMMAND_TYPE() ;
      errlog_rec.errnum := error_numbers(1) ;
      errlog_rec.errmsg := error_messages(1) ;
      INSERT INTO strmadmin.errorlog VALUES (SYSDATE, apply_name, 
           errlog_rec.sender, errlog_rec.object_name, errlog_rec.command_type, 
           errlog_rec.errnum, errlog_rec.errmsg, errlog_rec.text, lcr);
      -- Add the logic to change the contents of LCR with correct values.
      -- In this example, get a new region_id number 
      -- from the hr.reg_exception_s sequence.
      ov2 := lcr.GET_VALUES('new', 'n');
      FOR i IN 1 .. ov2.count
      LOOP
        IF ov2(i).column_name = 'REGION_ID' THEN
         SELECT hr.reg_exception_s.NEXTVAL INTO reg_id FROM DUAL; 
         ov2(i).data := ANYDATA.ConvertNumber(reg_id) ;
        END IF ;
      END LOOP ;
      -- Set the NEW values in the LCR.
      lcr.SET_VALUES(value_type => 'NEW', value_list => ov2);
      -- Execute the modified LCR to apply it.
      lcr.EXECUTE(TRUE);
     END regions_pk_error;
    END errors_pkg;
    /
    

注意:

  • 変更された行に対する以降の変更が正常に適用されるように、2つのデータベースの行をできるだけ迅速に収束する必要があります。つまり、ソース・データベースと宛先データベースの行のregion_idを一致させる必要があります。このような手動での変更をデータベースで再取得させないようにする場合は、DBMS_STREAMSパッケージのSET_TAGプロシージャを使用して、取得されない値を変更するセッション用のタグを設定します。

  • この例のエラー・ハンドラでは、LCRに対してGET_VALUESメンバー・ファンクションとSET_VALUESメンバー・プロシージャを使用しています。LCR内で変更する値が1つのみの場合は、GET_VALUESメンバー・ファンクションとSET_VALUEメンバー・プロシージャを使用する方が簡単で効率的な場合があります。



関連項目:

  • 現行セッションで生成されるタグの値の設定の詳細は、『Oracle Streamsレプリケーション管理者ガイド』を参照

  • エラー・ハンドラで処理する特定のエラー・メッセージの詳細は、「エラー・キューに適用エラーがあるか」を参照


エラー・ハンドラの設定

エラー・ハンドラは、任意の適用プロセスによってデキューされた、指定の表に対する指定の操作を含む行LCRから生成されたエラーを処理します。同一の表に対する様々な操作で生成されるエラーを処理するために、表に複数のエラー・ハンドラを指定できます。特定の適用プロセスにエラー・ハンドラを設定できます。また、指定の表に指定の操作を適用するすべての適用プロセスで使用される一般的なエラー・ハンドラとして、エラー・ハンドラを設定することもできます。

エラー・ハンドラを設定するには、DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを使用します。このプロシージャを実行してエラー・ハンドラを設定する場合は、error_handlerパラメータをTRUEに設定します。

たとえば、次のプロシージャでは、hr.regions表に対するINSERT操作用のエラー・ハンドラを設定します。したがって、適用プロセスによって、ローカルのhr.regions表に対するINSERT操作を含む行LCRがデキューされ、行LCRがエラーになると、適用プロセスでは、行LCRがstrmadmin.errors_pkg.regions_pk_error PL/SQLプロシージャに送信されて処理されます。エラー・ハンドラでエラーを解決できない場合は、その行LCRと、同じトランザクション内の他のすべての行LCRがエラー・キューに移動されます。

この例では、apply_nameパラメータがNULLに設定されています。したがって、エラー・ハンドラは、データベース内のすべての適用プロセスで使用される汎用エラー・ハンドラになります。

次のプロシージャを実行してエラー・ハンドラを設定します。

BEGIN
  DBMS_APPLY_ADM.SET_DML_HANDLER(
    object_name         => 'hr.regions',
    object_type         => 'TABLE',
    operation_name      => 'INSERT',
    error_handler       => TRUE,
    user_procedure      => 'strmadmin.errors_pkg.regions_pk_error',
    apply_database_link => NULL,
    apply_name          => NULL);
END;
/

エラー・ハンドラがすでに設定されている場合は、SET_DML_HANDLERプロシージャを実行してエラー・ハンドラを変更できます。

エラー・ハンドラの設定解除

エラー・ハンドラの設定を解除するには、DBMS_APPLY_ADMパッケージのSET_DML_HANDLERプロシージャを使用します。このプロシージャを実行するときに、特定の表に対する特定の操作について、user_procedureパラメータをNULLに設定します。

たとえば、次のプロシージャでは、hr.regions表に対するINSERT操作について、エラー・ハンドラの設定が解除されます。

BEGIN
  DBMS_APPLY_ADM.SET_DML_HANDLER(
    object_name    => 'hr.regions',
    object_type    => 'TABLE',
    operation_name => 'INSERT',
    user_procedure => NULL,
    apply_name     => NULL);
END;
/

注意:

error_handlerパラメータを指定する必要はありません。

適用エラーの管理

次の各項では、適用エラーの再試行と削除の手順について説明します。


関連項目:


適用エラー・トランザクションの再試行

特定のエラー・トランザクション、または適用プロセスのすべてのエラー・トランザクションを再試行できます。場合によっては、エラー・トランザクションを再試行する前に、データベース・オブジェクトに対してDML変更またはDDL変更を行い、1つ以上の適用エラーの原因となった状態を修正する必要があります。また、同じデータベース・オブジェクトに対する変更を取得するように1つ以上の取得プロセスまたは同期取得を構成しているときに、変更の取得が不要になる可能性があります。この場合は、変更を行うセッションのセッション・タグを、取得されない値に設定できます。


関連項目:

現行セッションで生成されるタグの値の設定の詳細は、『Oracle Streamsレプリケーション管理者ガイド』を参照

特定の適用エラー・トランザクションの再試行

エラー・トランザクションを再試行する場合は、直接実行することも、ユーザー・プロシージャにエラー・トランザクションを送信して変更した後で実行することもできます。次の各項では、各方法の手順について説明します。


関連項目:

EXECUTE_ERRORプロシージャの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照

ユーザー・プロシージャを使用しない特定の適用エラー・トランザクションの再試行

適用エラーの原因となった条件を修正した後に、ユーザー・プロシージャを指定せずにDBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを実行して、トランザクションを再試行できます。この場合、トランザクションはカスタム処理を使用せずに実行されます。

たとえば、トランザクション識別子が5.4.312のトランザクションを再試行するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.EXECUTE_ERROR(
    local_transaction_id => '5.4.312',
    execute_as_user      => FALSE,
    user_procedure       => NULL);
END;
/

execute_as_userTRUEの場合は、適用プロセスでは、現行ユーザーのセキュリティ・コンテキスト内でトランザクションが実行されます。execute_as_userFALSEの場合、適用プロセスでは、トランザクションの元の受信者のセキュリティ・コンテキスト内でトランザクションが実行されます。元の受信者は、エラー発生時にトランザクションを処理していたユーザーです。

いずれの場合も、トランザクションを実行するユーザーには、適用オブジェクトに対するDML変更およびDDL変更を実行するための権限と、任意の適用ハンドラを実行するための権限が必要です。また、このユーザーには、適用プロセスで使用されるキューに対するデキュー権限も必要です。

ユーザー・プロシージャを使用した特定の適用エラー・トランザクションの再試行

DBMS_APPLY_ADMパッケージのEXECUTE_ERRORプロシージャを実行してエラー・トランザクションを再試行できます。また、ユーザー・プロシージャを指定して、トランザクションの実行前に、トランザクション内の1つ以上のメッセージを変更することもできます。この変更によって、トランザクションが正常に実行できるはずです。トランザクション内のメッセージは、LCRまたはユーザー・メッセージです。

たとえば、競合のために適用エラーが発生したとします。エラー・トランザクションを検証すると、行LCRのsalary列の古い値が間違っていることが判明しました。具体的には、hr.employees表のemployee_id197の従業員について、給料の現行の値が、行LCRにおけるこの従業員の給料の古い値と一致していません。hr.employees表で、この従業員の現行の値が3250であるとします。

この場合、次のユーザー・プロシージャで、エラーの原因となった行LCRの給料を変更します。

CREATE OR REPLACE PROCEDURE strmadmin.modify_emp_salary(
  in_any                        IN      ANYDATA,
  error_record                  IN      DBA_APPLY_ERROR%ROWTYPE,
  error_message_number          IN      NUMBER,
  messaging_default_processing  IN OUT  BOOLEAN,
  out_any                       OUT     ANYDATA)
AS
  row_lcr          SYS.LCR$_ROW_RECORD;
  row_lcr_changed  BOOLEAN := FALSE;
  res              NUMBER;
  ob_owner         VARCHAR2(32);
  ob_name          VARCHAR2(32);
  cmd_type         VARCHAR2(30);
  employee_id      NUMBER;
BEGIN
  IF in_any.getTypeName() = 'SYS.LCR$_ROW_RECORD' THEN
    -- Access the LCR
    res := in_any.GETOBJECT(row_lcr);
    -- Determine the owner of the database object for the LCR
    ob_owner := row_lcr.GET_OBJECT_OWNER;
    -- Determine the name of the database object for the LCR
    ob_name := row_lcr.GET_OBJECT_NAME;
    -- Determine the type of DML change
    cmd_type := row_lcr.GET_COMMAND_TYPE;
    IF (ob_owner = 'HR' AND ob_name = 'EMPLOYEES' AND cmd_type = 'UPDATE') THEN
      -- Determine the employee_id of the row change
      IF row_lcr.GET_VALUE('old', 'employee_id') IS NOT NULL THEN
        employee_id := row_lcr.GET_VALUE('old', 'employee_id').ACCESSNUMBER();
        IF (employee_id = 197) THEN
          -- error_record.message_number should equal error_message_number
          row_lcr.SET_VALUE(
          value_type => 'OLD',
          column_name => 'salary',
          column_value => ANYDATA.ConvertNumber(3250));
          row_lcr_changed := TRUE;
        END IF;
      END IF;
    END IF;
  END IF;
  -- Specify that the apply process continues to process the current message
  messaging_default_processing := TRUE;
  -- assign out_any appropriately
  IF row_lcr_changed THEN
    out_any := ANYDATA.ConvertObject(row_lcr);
  ELSE
    out_any := in_any;
  END IF;
END;
/

トランザクション識別子が5.6.924のトランザクションを再試行する際、実行前にstrmadminスキーマ内のmodify_emp_salaryプロシージャでトランザクションを処理するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.EXECUTE_ERROR(
    local_transaction_id => '5.6.924',
    execute_as_user      => FALSE,
    user_procedure       => 'strmadmin.modify_emp_salary');
END;
/

注意:

プロシージャを実行するユーザーは、DBA_APPLY_ERRORデータ・ディクショナリ・ビューに対するSELECT権限を持っている必要があります。

適用プロセスのすべてのエラー・トランザクションの再試行

適用プロセスについて、すべての適用エラーの原因となった条件を修正した後に、DBMS_APPLY_ADMパッケージのEXECUTE_ALL_ERRORSプロシージャを実行してすべてのエラー・トランザクションを再試行できます。たとえば、適用プロセスstrm01_applyのすべてのエラー・トランザクションを再試行するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.EXECUTE_ALL_ERRORS(
    apply_name       => 'strm01_apply',
    execute_as_user  => FALSE);
END;
/

注意:

apply_nameパラメータに対してNULLを指定した場合に、複数の適用プロセスが存在すると、すべての適用プロセスのすべての適用エラーが再試行されます。

適用エラー・トランザクションの削除

特定のエラー・トランザクションまたは適用プロセスのすべてのエラー・トランザクションを削除できます。

特定の適用エラー・トランザクションの削除

エラー・トランザクションを適用する必要がない場合は、DBMS_APPLY_ADMパッケージのDELETE_ERRORプロシージャを使用して、エラー・キューからトランザクションを削除できます。たとえば、トランザクション識別子が5.4.312のトランザクションを削除するには、次のプロシージャを実行します。

EXEC DBMS_APPLY_ADM.DELETE_ERROR(local_transaction_id => '5.4.312');

適用プロセスのすべてのエラー・トランザクションの削除

すべてのエラー・トランザクションを適用しない場合は、DBMS_APPLY_ADMパッケージのDELETE_ALL_ERRORSプロシージャを実行して、すべてのエラー・トランザクションを削除できます。たとえば、適用プロセスstrm01_applyのすべてのエラー・トランザクションを削除するには、次のプロシージャを実行します。

EXEC DBMS_APPLY_ADM.DELETE_ALL_ERRORS(apply_name => 'strm01_apply');

注意:

apply_nameパラメータに対してNULLを指定した場合に、複数の適用プロセスが存在すると、すべての適用プロセスのすべての適用エラーが削除されます。

表の代替キー列の管理

この項では、表の代替キー列の設定および削除の手順について説明します。

表の代替キー列の設定

適用プロセスによって表に変更が適用される場合、代替キー列は、主キーを含む表の主キー列と置き換えられるか、または主キーを含まない表の主キー列として使用できます。表の代替キー列を設定するには、DBMS_APPLY_ADMパッケージのSET_KEY_COLUMNSプロシージャを使用します。この設定は、ローカルの変更をデータベースに適用する適用プロセスすべてに適用されます。

たとえば、hr.employees表の代替キー列をfirst_namelast_nameおよびhire_dateの各列に設定して、employee_id列を置換するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_KEY_COLUMNS(
    object_name         => 'hr.employees',
    column_list         => 'first_name,last_name,hire_date');
END;
/

注意:

  • 宛先データベースのcolumn_listまたはcolumn_tableパラメータで代替キー列として指定されたすべての列に対して、ソース・データベースで無条件サプリメンタル・ログ・グループを指定する必要があります。この例では、hr.employees表のfirst_namelast_nameおよびhire_date列を含む無条件サプリメンタル・ログ・グループを指定します。

  • 適用プロセスによってOracle以外のリモート・データベースに変更が適用される場合、この適用プロセスでは、同じ表に対して別の代替キー列を使用できます。DBMS_APPLY_ADMパッケージのSET_KEY_COLUMNSプロシージャを実行して、apply_database_linkパラメータをNULL以外の値に設定することにより、Oracle以外のリモート・データベースに適用される変更に対して代替キー列を指定できます。



関連項目:


表の代替キー列の削除

表の代替キー列を削除するには、DBMS_APPLY_ADMパッケージのSET_KEY_COLUMNSプロシージャでcolumn_listまたはcolumn_tableパラメータにNULLを指定します。表に主キーがある場合、代替主キーを削除すると、適用プロセスではデータベースに対するローカルの変更にその表の主キーが使用されます。

たとえば、hr.employees表の代替キー列を削除するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_KEY_COLUMNS(
    object_name  => 'hr.employees',
    column_list  => NULL);
END;
/

仮想依存性定義の使用

仮想依存性定義とは、宛先データベースで適用されるトランザクション間の依存性を検出するために、適用プロセスで使用される依存性の記述です。仮想依存性定義は、適用プロセスの並列性が1より大きく、依存性が宛先データベースのデータ・ディクショナリに制約によって記述されていない場合に役立ちます。仮想依存性定義には、値の依存性とオブジェクト依存性の2つのタイプがあります。

値の依存性は、一意キーなどの表制約、または2つ以上の表の列間の関連を定義します。オブジェクト依存性は、宛先データベースの2つのオブジェクト間の親子関係を定義します。

次の各項では、仮想依存性定義の使用について説明します。


関連項目:

仮想依存性定義の詳細は、「適用プロセスおよび依存性」を参照

値の依存性の設定および設定解除

DBMS_APPLY_ADMパッケージのSET_VALUE_DEPENDENCYプロシージャを使用して、値の依存性を設定または設定解除します。次の各項では、値の依存性を使用する場合の使用例について説明します。

スキーマの相違および値の依存性

この使用例に関連する環境では、ソース・データベースと宛先データベースの間で数多くの表を共有するものの、これら2つのデータベースで表を所有するスキーマが異なっています。また、このレプリケーション環境では、ソース・データベースが米国に存在し、宛先データベースが英国に存在します。ある設計会社が製品設計を作成するのに多くの表を使用していますが、ソース・データベースの表では米国の測定単位(インチ、フィートなど)が使用され、宛先データベースの表ではメートル法の測定単位が使用されています。ソース・データベースでデータベース・オブジェクトを所有するスキーマの名前はus_designs、宛先データベースでのスキーマの名前はuk_designsです。したがって、適用前に共有データベース・オブジェクトのスキーマ名を変更する必要があり、すべての測定単位を米国の測定単位からメートル法の測定単位に変換する必要があります。データベース・オブジェクト間に依存性を持たせるために、両方のデータベースで同じ制約を使用します。

必要となる変更はルールベースの変換を使用して行うことができますが、ここでの目的は複数のLCRをパラレルで適用することです。ルールベースの変換では、LCRをシリアルに適用する必要があります。そのため、宛先データベースでのプロシージャDMLハンドラがLCRに必要な変更を行うように構成され、適用プロセスの並列性が5に設定されます。この環境では、宛先データベースにはソース・データベースから送信されるLCRのスキーマus_designsに関する情報がありません。適用プロセスではLCRを適用ハンドラに渡す前に依存性を計算するため、適用プロセスにLCR間の依存性に関する情報が通知される必要があります。値の依存性を使用すると、これらの依存性を記述できます。

この使用例では、複数の表で異なる設計が作成され、これらの表にそれぞれ主キーが存在するとします。これらの表の1つにdesign_53があり、その主キー列はkey_53です。また、表all_designs_summaryには個別の設計すべての概要が含まれ、この表には各設計表の外部キー列が含まれます。all_designs_summaryには、design_53表の主キーの外部キーであるkey_53列が含まれます。これらの表の関係について適用プロセスに通知するには、次のプロシージャを実行して、宛先データベースで値の依存性を作成します。

BEGIN
  DBMS_APPLY_ADM.SET_VALUE_DEPENDENCY(
    dependency_name   => 'key_53_foreign_key',
    object_name       => 'us_designs.design_53',
    attribute_list    => 'key_53');
END;
/
BEGIN
  DBMS_APPLY_ADM.SET_VALUE_DEPENDENCY(
    dependency_name   => 'key_53_foreign_key',
    object_name       => 'us_designs.all_designs_summary',
    attribute_list    => 'key_53');
END;
/

LCRにはソース・データベースのスキーマが含まれるため、値の依存性でそのソース・データベースのスキーマ(us_designs)が使用されていることに注意してください。適用プロセスによって行LCRがハンドラに渡された後、プロシージャDMLハンドラによってスキーマがuk_designsに変更されます。

値の依存性を設定解除するには、SET_VALUE_DEPENDENCYプロシージャを実行して、dependency_nameパラメータに値の依存性の名前を指定し、object_nameパラメータにNULLを指定します。たとえば、以前に設定した値の依存性key_53_foreign_keyを設定解除するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_VALUE_DEPENDENCY(
    dependency_name   => 'key_53_foreign_key',
    object_name       => NULL,
    attribute_list    => NULL);
END;
/

宛先データベースでの未定義の制約および値の依存性

この使用例に関連する環境では、ソース・データベースの共有表に対して外部キー制約が使用され、宛先データベースのこれらの表に対しては制約が使用されていません。このレプリケーション環境では、宛先データベースがデータ・ウェアハウスとして使用されており、問合せよりもデータベースへのデータの書込みの方がはるかに頻繁に行われます。書込み操作を最適化するために、宛先データベースでは制約が定義されていません。

このような環境では、トランザクションを一貫して適用するために、宛先データベースで実行中の適用プロセスに制約について通知する必要があります。値の依存性を使用すると、適用プロセスにこれらの制約について通知できます。

たとえば、oeスキーマ内のordersおよびorder_items表が、この環境のソース・データベースと宛先データベース間で共有されているとします。ソース・データベースでは、order_id列はorders表の主キーであり、order_items表のorder_id列はorders表の主キー列と一致する外部キーです。宛先データベースでは、これらの制約は削除されています。次のプロシージャを実行し、適用プロセスにこれらの表の列の関係について通知する値の依存性を宛先データベースで作成します。

BEGIN
  DBMS_APPLY_ADM.SET_VALUE_DEPENDENCY(
    dependency_name   => 'order_id_foreign_key',
    object_name       => 'oe.orders',
    attribute_list    => 'order_id');
END;
/
BEGIN
  DBMS_APPLY_ADM.SET_VALUE_DEPENDENCY(
    dependency_name   => 'order_id_foreign_key',
    object_name       => 'oe.order_items',
    attribute_list    => 'order_id');
END;
/

また、この環境では、適用プロセスでトランザクションが一貫して適用できるように、次のアクションを実行する必要があります。

  • ソース・データベースで一意キーまたはビットマップ索引を含む各列に対して値の依存性を設定する必要があります。

  • DBMS_APPLY_ADM.SET_KEY_COLUMNSプロシージャを実行して、ソース・データベースで主キー列である列の代替キー列を設定する必要があります。

以前に設定した値の依存性を設定解除するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.SET_VALUE_DEPENDENCY(
    dependency_name   => 'order_id_foreign_key',
    object_name       => NULL,
    attribute_list    => NULL);
END;
/

オブジェクト依存性の作成および削除

DBMS_APPLY_ADMパッケージのCREATE_OBJECT_DEPENDENCYおよびDROP_OBJECT_DEPENDENCYプロシージャを実行して、オブジェクト依存性を作成または削除します。次の各項では、オブジェクト依存性の作成および削除の詳しい手順について説明します。

オブジェクト依存性の作成

特定の表の行LCRが常に別の表の行LCRより前に適用される必要があり、宛先データベースのデータ・ディクショナリにこの関係を持たせる制約が含まれていない場合に、オブジェクト依存性を使用できます。オブジェクト依存性を定義する場合、最初に適用される必要がある行LCRを含む表が親表であり、2番目に適用される必要がある行LCRを含む表が子表です。

たとえば、次の特性を持つOracle Streamsレプリケーション環境を考えます。

  • ordスキーマ内の次の表はソース・データベースと宛先データベース間で共有されます。

    • customers表には、顧客に関する情報(各顧客の出荷先住所など)が含まれます。

    • orders表には、各注文に関する情報が含まれます。

    • order_items表には、各注文内のアイテムに関する情報が含まれます。

    • ship_orders表には、出荷の準備が完了している注文に関する情報は含まれますが、顧客の詳細情報または各注文で出荷される個別のアイテムに関する情報は含まれません。

  • ship_orders表には、制約によって定義された、他の表との関係は存在しません。

  • 注文に関する情報はソース・データベースに入力され、宛先データベースに伝播されて適用されます。

  • 宛先データベースのサイトは注文が顧客に出荷されるウェアハウスです。このサイトで、プロシージャDMLハンドラによってship_orderscustomersordersおよびorder_itemsの各表の情報が使用され、顧客の出荷先住所と出荷するアイテムを含むレポートが生成されます。

プロシージャDMLハンドラによって生成されたレポートの情報は、出荷注文記録が作成された時間と一貫性がある必要があります。宛先データベースのオブジェクト依存性によって、この目的が達成されます。この場合、ship_orders表は子表customersordersおよびorder_itemsの親表です。ship_ordersがこれらの表の親であるため、ship_orders表の記録が入力された後にこれらの表に対して行われた変更は、プロシージャDMLハンドラによって出荷注文のレポートが生成されるまで適用されません。

これらのオブジェクト依存性を作成するには、宛先データベースで次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.CREATE_OBJECT_DEPENDENCY(
    object_name         =>  'ord.customers',
    parent_object_name  =>  'ord.ship_orders');
END;
/
BEGIN
  DBMS_APPLY_ADM.CREATE_OBJECT_DEPENDENCY(
    object_name         =>  'ord.orders',
    parent_object_name  =>  'ord.ship_orders');
END;
/
BEGIN
  DBMS_APPLY_ADM.CREATE_OBJECT_DEPENDENCY(
    object_name         =>  'ord.order_items',
    parent_object_name  =>  'ord.ship_orders');
END;
/

オブジェクト依存性の削除

「オブジェクト依存性の作成」で作成したオブジェクト依存性を削除するには、次のプロシージャを実行します。

BEGIN
  DBMS_APPLY_ADM.DROP_OBJECT_DEPENDENCY(
    object_name         =>  'ord.customers',
    parent_object_name  =>  'ord.ship_orders');
END;
/
BEGIN
  DBMS_APPLY_ADM.DROP_OBJECT_DEPENDENCY(
    object_name         =>  'ord.orders',
    parent_object_name  =>  'ord.ship_orders');
END;
/
BEGIN
  DBMS_APPLY_ADM.DROP_OBJECT_DEPENDENCY(
    object_name         =>  'ord.order_items',
    parent_object_name  =>  'ord.ship_orders');
END;
/

適用プロセスの削除

既存の適用プロセスを削除するには、DBMS_APPLY_ADMパッケージのDROP_APPLYプロシージャを実行します。たとえば、次のプロシージャでは、適用プロセスstrm02_applyが削除されます。

BEGIN
  DBMS_APPLY_ADM.DROP_APPLY(
    apply_name            => 'strm02_apply',
    drop_unused_rule_sets => TRUE);
END;
/

drop_unused_rule_setsパラメータがTRUEに設定されているため、このプロシージャではstrm02_apply適用プロセスで使用されているルール・セットも削除されます。ただし、他のOracle Streamsクライアントで使用されているルール・セットは削除されません。drop_unused_rule_setsパラメータがTRUEに設定されている場合は、適用プロセスのポジティブ・ルール・セットとネガティブ・ルール・セットの両方が削除されることがあります。このプロシージャによってルール・セットが削除された場合、そのルール・セット内のルールのうち、他のルール・セットに含まれていないルールも削除されます。

適用プロセスを削除しようとしたときに、指定した適用プロセスのエラー・キューにエラーが存在すると、エラーが発生します。このため、適用プロセスのエラー・キューにエラーが存在する場合は、適用プロセスを削除する前にエラーを削除します。