この章では、Oracle Streamsレプリケーション環境で論理変更レコード(LCR)を管理する方法について説明します。
この章の内容は次のとおりです。
|
関連項目: LCRの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』および『Oracle Streams概要および管理』を参照してください。 |
この項では、論理変更レコード(LCR)を作成または変更するための要件について説明します。LCR型のコンストラクタを使用してLCRを作成し、そのLCRをANYDATAキューの永続キュー部分にエンキューできます。このようなLCRは、永続LCRです。
また、適用ハンドラまたはルールベースの変換を使用して、LCRを変更できます。取得LCRまたは永続LCRを変更できます。
LCRを管理するときには、次の要件を満たしていることを確認してください。
行LCRを作成または変更する場合は、command_type属性に古い列値の有無および新しい列値の有無との一貫性があることを確認してください。
DDL LCRを作成または変更する場合は、ddl_textがbase_table_name、base_table_owner、object_type、object_owner、object_nameおよびcommand_type属性と一貫していることを確認してください。
ユーザーが構成する行LCRの列に許可されるデータ型は、次のとおりです。
CHAR
VARCHAR2
NCHAR
NVARCHAR2
NUMBER
DATE
BINARY_FLOAT
BINARY_DOUBLE
RAW
TIMESTAMP
TIMESTAMP WITH TIME ZONE
TIMESTAMP WITH LOCAL TIME ZONE
INTERVAL YEAR TO MONTH
INTERVAL DAY TO SECOND
ユーザーが構成する行LCRの列に許可されるデータ型は、これらのデータ型のみです。ただし、特定の方法を使用すると、LOB情報を含むLCRを構成できます。また、取得プロセスによって取得されるLCRでは、サポートされるデータ型がより多くなっていますが、同期取得によって取得されるLCRでは、サポートされるデータ型がより少なくなっています。
|
関連項目:
|
次のLCRコンストラクタを使用してLCRを作成します。
データ操作言語(DML)文によって生じた行に対する変更を含む行LCRを作成するには、SYS.LCR$_ROW_RECORDコンストラクタを使用します。
データ定義言語(DDL)変更を含むDDL LCRを作成するには、SYS.LCR$_DDL_RECORDコンストラクタを使用します。各DDL LCRのddl_text属性に指定するDDLテキストが、Oracle SQL構文に準拠していることを確認してください。
次の例では、Oracle Database内のキューと、そのキューに関連付けられた適用プロセスを作成します。次に、渡された情報に基づいて行LCRを構成し、それをキューにエンキューするPL/SQLプロシージャを作成します。この例では、Oracle Streams管理者strmadminを構成して、この管理者にDBAロールを付与していると想定しています。
手順は次のとおりです。
SQL*Plusで、管理ユーザーとしてデータベースに接続します。
SQL*Plusでデータベースに接続する手順については、『Oracle Database管理者ガイド』を参照してください。
Oracle Streams管理者にDBMS_STREAMS_MESSAGINGパッケージに対するEXECUTE権限を付与します。次に例を示します。
GRANT EXECUTE ON DBMS_STREAMS_MESSAGING TO strmadmin;
手順9のPL/SQLプロシージャ内でこのパッケージのプロシージャをコールするため、このパッケージに対する明示的なEXECUTE権限が必要です。この場合、ロールを介して権限を付与するのみでは不十分です。
SQL*Plusで、Oracle Streams管理者としてデータベースに接続します。
Oracle DatabaseにANYDATAキューを作成します。
BEGIN
DBMS_STREAMS_ADM.SET_UP_QUEUE(
queue_table => 'strm04_queue_table',
storage_clause => NULL,
queue_name => 'strm04_queue');
END;
/
キュー内のメッセージを受信するOracle Databaseで、適用プロセスを作成します。適用プロセスでは、取得LCRではなく永続LCRが適用されるため、この適用プロセスの作成時には、apply_capturedパラメータをFALSEに設定してください。また、hr.regions表に変更が適用され、適用ユーザーにはこの表にDML変更を加える権限が必要であるため、apply_userパラメータがhrに設定されていることを確認してください。
BEGIN
DBMS_APPLY_ADM.CREATE_APPLY(
queue_name => 'strm04_queue',
apply_name => 'strm04_apply',
apply_captured => FALSE,
apply_user => 'hr');
END;
/
適用プロセスのポジティブ・ルール・セットを作成し、DML変更をdbs1.example.comソース・データベースに作成されたhr.regions表に適用するルールを追加します。
BEGIN
DBMS_STREAMS_ADM.ADD_TABLE_RULES(
table_name => 'hr.regions',
streams_type => 'apply',
streams_name => 'strm04_apply',
queue_name => 'strm04_queue',
include_dml => TRUE,
include_ddl => FALSE,
include_tagged_lcr => FALSE,
source_database => 'dbs1.example.com',
inclusion_rule => TRUE);
END;
/
適用プロセスのdisable_on_errorパラメータをnに設定します。
BEGIN
DBMS_APPLY_ADM.SET_PARAMETER(
apply_name => 'strm04_apply',
parameter => 'disable_on_error',
value => 'N');
END;
/
適用プロセスを起動します。
EXEC DBMS_APPLY_ADM.START_APPLY('strm04_apply');
行LCRを構成して手順4で作成したキューにエンキューするプロシージャconstruct_row_lcrを作成します。
CREATE OR REPLACE PROCEDURE construct_row_lcr(
source_dbname VARCHAR2,
cmd_type VARCHAR2,
obj_owner VARCHAR2,
obj_name VARCHAR2,
old_vals SYS.LCR$_ROW_LIST,
new_vals SYS.LCR$_ROW_LIST) AS
row_lcr SYS.LCR$_ROW_RECORD;
BEGIN
-- Construct the LCR based on information passed to procedure
row_lcr := SYS.LCR$_ROW_RECORD.CONSTRUCT(
source_database_name => source_dbname,
command_type => cmd_type,
object_owner => obj_owner,
object_name => obj_name,
old_values => old_vals,
new_values => new_vals);
-- Enqueue the created row LCR
DBMS_STREAMS_MESSAGING.ENQUEUE(
queue_name => 'strm04_queue',
payload => ANYDATA.ConvertObject(row_lcr));
END construct_row_lcr;
/
|
注意: トランザクション識別子やSCNは適用プロセスで生成されてメモリーに格納されるため、これらの値をLCRの作成時にアプリケーションで指定する必要はありません。LCRでトランザクション識別子またはSCNを指定しても、適用プロセスでは無視され、新規の値が割り当てられます。 |
|
関連項目: LCRコンストラクタの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。 |
手順5で作成したconstruct_row_lcrプロシージャを使用してLCRを作成し、エンキューします。
SQL*Plusで、Oracle Streams管理者としてデータベースに接続します。
hr.regions表に1行を挿入する行LCRを作成します。
DECLARE
newunit1 SYS.LCR$_ROW_UNIT;
newunit2 SYS.LCR$_ROW_UNIT;
newvals SYS.LCR$_ROW_LIST;
BEGIN
newunit1 := SYS.LCR$_ROW_UNIT(
'region_id',
ANYDATA.ConvertNumber(5),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
newunit2 := SYS.LCR$_ROW_UNIT(
'region_name',
ANYDATA.ConvertVarchar2('Moon'),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
newvals := SYS.LCR$_ROW_LIST(newunit1,newunit2);
construct_row_lcr(
source_dbname => 'dbs1.example.com',
cmd_type => 'INSERT',
obj_owner => 'hr',
obj_name => 'regions',
old_vals => NULL,
new_vals => newvals);
END;
/
COMMIT;
SQL*Plusで、hrユーザーとしてデータベースに接続します。
hr.regions表を問い合せて、適用済の行の変更を表示します。region_idが5である行は、region_nameがMoonとなっているはずです。
SELECT * FROM hr.regions;
SQL*Plusで、Oracle Streams管理者としてデータベースに接続します。
hr.regions表から1行を更新する行LCRを作成します。
DECLARE
oldunit1 SYS.LCR$_ROW_UNIT;
oldunit2 SYS.LCR$_ROW_UNIT;
oldvals SYS.LCR$_ROW_LIST;
newunit1 SYS.LCR$_ROW_UNIT;
newvals SYS.LCR$_ROW_LIST;
BEGIN
oldunit1 := SYS.LCR$_ROW_UNIT(
'region_id',
ANYDATA.ConvertNumber(5),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldunit2 := SYS.LCR$_ROW_UNIT(
'region_name',
ANYDATA.ConvertVarchar2('Moon'),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldvals := SYS.LCR$_ROW_LIST(oldunit1,oldunit2);
newunit1 := SYS.LCR$_ROW_UNIT(
'region_name',
ANYDATA.ConvertVarchar2('Mars'),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
newvals := SYS.LCR$_ROW_LIST(newunit1);
construct_row_lcr(
source_dbname => 'dbs1.example.com',
cmd_type => 'UPDATE',
obj_owner => 'hr',
obj_name => 'regions',
old_vals => oldvals,
new_vals => newvals);
END;
/
COMMIT;
SQL*Plusで、hrユーザーとしてデータベースに接続します。
hr.regions表を問い合せて、適用済の行の変更を表示します。region_idが5である行は、region_nameがMarsとなっているはずです。
SELECT * FROM hr.regions;
hr.regions表から1行を削除する行LCRを作成します。
DECLARE
oldunit1 SYS.LCR$_ROW_UNIT;
oldunit2 SYS.LCR$_ROW_UNIT;
oldvals SYS.LCR$_ROW_LIST;
BEGIN
oldunit1 := SYS.LCR$_ROW_UNIT(
'region_id',
ANYDATA.ConvertNumber(5),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldunit2 := SYS.LCR$_ROW_UNIT(
'region_name',
ANYDATA.ConvertVarchar2('Mars'),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldvals := SYS.LCR$_ROW_LIST(oldunit1,oldunit2);
construct_row_lcr(
source_dbname => 'dbs1.example.com',
cmd_type => 'DELETE',
obj_owner => 'hr',
obj_name => 'regions',
old_vals => oldvals,
new_vals => NULL);
END;
/
COMMIT;
SQL*Plusで、hrユーザーとしてデータベースに接続します。
hr.regions表を問い合せて、適用済の行の変更を表示します。region_idが5である行は、削除されているはずです。
SELECT * FROM hr.regions;
行LCRおよびDDL LCR用に、個別のEXECUTEメンバー・プロシージャがあります。これらのメンバー・プロシージャを使用すると、現行ユーザーのセキュリティ・ドメインでLCRが実行されます。LCRが正常に実行されると、LCRに記録された変更がローカル・データベースに対して行われます。ここでは、行LCRおよびDDL LCRの実行について説明します。
行LCR用のEXECUTEメンバー・プロシージャは、LCR$_ROW_RECORD型のサブプログラムです。行LCRにEXECUTEメンバー・プロシージャを実行すると、行LCRが実行されます。行LCRが適用プロセスによって実行される場合、LCRに対して実行される適用プロセスのハンドラは実行されません。
次のいずれかの条件が満たされる場合は、行LCRにEXECUTEメンバー・プロシージャを実行できます。
LCRが適用ハンドラによって処理されている。
LCRがキューに存在し、このLCRが適用プロセス、アプリケーションまたはユーザーによって最後にエンキューされたLCRである。
LCRがLCR$_ROW_RECORDコンストラクタ・ファンクションを使用して構成されているが、エンキューされていない。
LCRがエラー・キューに存在する。
行LCRにEXECUTEメンバー・プロシージャを実行する場合、競合解消を実行するかどうかをconflict_resolutionパラメータで制御します。具体的には、conflict_resolutionパラメータをTRUEに設定した場合、変更対象の表に定義されている競合解消を使用して、LCRの実行によって発生する競合が解消されます。conflict_resolutionパラメータをFALSEに設定した場合、競合解消は使用されません。conflict_resolutionパラメータを設定しない場合、またはNULLに設定した場合は、エラーが発生します。
|
注意: カスタム・ルールベースの変換では、行LCRにEXECUTEメンバー・プロシージャを実行しないでください。実行すると、トランザクション・コンテキストの外部で行LCRが実行される場合があります。 |
|
関連項目:
|
この項の例では、PL/SQLプロシージャを作成し、行LCRを構成および実行することによってhr.jobs表の行の挿入、更新および削除を実行します。行LCRは、適用プロセスによってエンキューまたは処理されずに実行されます。この例では、Oracle Streams管理者strmadminを構成して、この管理者にDBAロールを付与していると想定しています。
手順は次のとおりです。
SQL*Plusで、Oracle Streams管理者としてデータベースに接続します。
SQL*Plusでデータベースに接続する手順については、『Oracle Database管理者ガイド』を参照してください。
行LCRを実行するPL/SQLプロシージャexecute_row_lcrを作成します。
CREATE OR REPLACE PROCEDURE execute_row_lcr(
source_dbname VARCHAR2,
cmd_type VARCHAR2,
obj_owner VARCHAR2,
obj_name VARCHAR2,
old_vals SYS.LCR$_ROW_LIST,
new_vals SYS.LCR$_ROW_LIST) as
xrow_lcr SYS.LCR$_ROW_RECORD;
BEGIN
-- Construct the row LCR based on information passed to procedure
xrow_lcr := SYS.LCR$_ROW_RECORD.CONSTRUCT(
source_database_name => source_dbname,
command_type => cmd_type,
object_owner => obj_owner,
object_name => obj_name,
old_values => old_vals,
new_values => new_vals);
-- Execute the row LCR
xrow_lcr.EXECUTE(FALSE);
END execute_row_lcr;
/
hr.jobs表に行を挿入する行LCRを実行するPL/SQLプロシージャinsert_job_lcrを作成します。
CREATE OR REPLACE PROCEDURE insert_job_lcr(
j_id VARCHAR2,
j_title VARCHAR2,
min_sal NUMBER,
max_sal NUMBER) AS
xrow_lcr SYS.LCR$_ROW_RECORD;
col1_unit SYS.LCR$_ROW_UNIT;
col2_unit SYS.LCR$_ROW_UNIT;
col3_unit SYS.LCR$_ROW_UNIT;
col4_unit SYS.LCR$_ROW_UNIT;
newvals SYS.LCR$_ROW_LIST;
BEGIN
col1_unit := SYS.LCR$_ROW_UNIT(
'job_id',
ANYDATA.ConvertVarchar2(j_id),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
col2_unit := SYS.LCR$_ROW_UNIT(
'job_title',
ANYDATA.ConvertVarchar2(j_title),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
col3_unit := SYS.LCR$_ROW_UNIT(
'min_salary',
ANYDATA.ConvertNumber(min_sal),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
col4_unit := SYS.LCR$_ROW_UNIT(
'max_salary',
ANYDATA.ConvertNumber(max_sal),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
newvals := SYS.LCR$_ROW_LIST(col1_unit,col2_unit,col3_unit,col4_unit);
-- Execute the row LCR
execute_row_lcr(
source_dbname => 'DB1.EXAMPLE.COM',
cmd_type => 'INSERT',
obj_owner => 'HR',
obj_name => 'JOBS',
old_vals => NULL,
new_vals => newvals);
END insert_job_lcr;
/
hr.jobs表の行のmax_salary値を更新する行LCRを実行するPL/SQLプロシージャupdate_max_salary_lcrを作成します。
CREATE OR REPLACE PROCEDURE update_max_salary_lcr(
j_id VARCHAR2,
old_max_sal NUMBER,
new_max_sal NUMBER) AS
xrow_lcr SYS.LCR$_ROW_RECORD;
oldcol1_unit SYS.LCR$_ROW_UNIT;
oldcol2_unit SYS.LCR$_ROW_UNIT;
newcol1_unit SYS.LCR$_ROW_UNIT;
oldvals SYS.LCR$_ROW_LIST;
newvals SYS.LCR$_ROW_LIST;
BEGIN
oldcol1_unit := SYS.LCR$_ROW_UNIT(
'job_id',
ANYDATA.ConvertVarchar2(j_id),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldcol2_unit := SYS.LCR$_ROW_UNIT(
'max_salary',
ANYDATA.ConvertNumber(old_max_sal),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldvals := SYS.LCR$_ROW_LIST(oldcol1_unit,oldcol2_unit);
newcol1_unit := SYS.LCR$_ROW_UNIT(
'max_salary',
ANYDATA.ConvertNumber(new_max_sal),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
newvals := SYS.LCR$_ROW_LIST(newcol1_unit);
-- Execute the row LCR
execute_row_lcr(
source_dbname => 'DB1.EXAMPLE.COM',
cmd_type => 'UPDATE',
obj_owner => 'HR',
obj_name => 'JOBS',
old_vals => oldvals,
new_vals => newvals);
END update_max_salary_lcr;
/
hr.jobs表から行を削除する行LCRを実行するPL/SQLプロシージャdelete_job_lcrを作成します。
CREATE OR REPLACE PROCEDURE delete_job_lcr(j_id VARCHAR2) AS
xrow_lcr SYS.LCR$_ROW_RECORD;
col1_unit SYS.LCR$_ROW_UNIT;
oldvals SYS.LCR$_ROW_LIST;
BEGIN
col1_unit := SYS.LCR$_ROW_UNIT(
'job_id',
ANYDATA.ConvertVarchar2(j_id),
DBMS_LCR.NOT_A_LOB,
NULL,
NULL);
oldvals := SYS.LCR$_ROW_LIST(col1_unit);
-- Execute the row LCR
execute_row_lcr(
source_dbname => 'DB1.EXAMPLE.COM',
cmd_type => 'DELETE',
obj_owner => 'HR',
obj_name => 'JOBS',
old_vals => oldvals,
new_vals => NULL);
END delete_job_lcr;
/
insert_job_lcrプロシージャを使用して、hr.jobs表に行を挿入します。
EXEC insert_job_lcr('BN_CNTR','BEAN COUNTER',5000,10000);
hr.jobs表に挿入された行を問い合せます。
SELECT * FROM hr.jobs WHERE job_id = 'BN_CNTR';
JOB_ID JOB_TITLE MIN_SALARY MAX_SALARY
---------- ----------------------------------- ---------- ----------
BN_CNTR BEAN COUNTER 5000 10000
update_max_salary_lcrプロシージャを使用して、手順6でhr.jobs表に挿入した行のmax_salary値を更新します。
EXEC update_max_salary_lcr('BN_CNTR',10000,12000);
hr.jobs表で更新された行を問い合せます。
SELECT * FROM hr.jobs WHERE job_id = 'BN_CNTR';
JOB_ID JOB_TITLE MIN_SALARY MAX_SALARY
---------- ----------------------------------- ---------- ----------
BN_CNTR BEAN COUNTER 5000 12000
delete_job_lcrプロシージャを使用して、手順6でhr.jobs表に挿入した行を削除します。
EXEC delete_job_lcr('BN_CNTR');
hr.jobs表から削除された行を問い合せます。
SELECT * FROM hr.jobs WHERE job_id = 'BN_CNTR';
no rows selected
DDL LCR用のEXECUTEメンバー・プロシージャは、LCR$_DDL_RECORD型のサブプログラムです。DDL LCRにEXECUTEメンバー・プロシージャを実行すると、LCRが実行され、LCRに対して実行される適用プロセスのハンドラは実行されません。DDL LCR用のEXECUTEメンバー・プロシージャを起動できるのは、適用プロセスの適用ハンドラ内のみです。
適用されたDDL LCRは、すべて自動的にコミットされます。したがって、DDLハンドラがDDL LCRのEXECUTEメンバー・プロシージャをコールすると、自動的にコミットが実行されます。
|
関連項目:
|
LOBデータ型は、取得プロセスによって取得される行LCRに存在できますが、他のデータ型として表されます。LOBデータ型は、同期取得によって取得される行LCRには存在できません。特定のLOBデータ型は、ユーザーが構成する行LCRには存在できません。表14-1に、これらのデータ型のLCR表現、および行LCRに存在できるかどうかを示します。
表14-1 行LCR内のLOBデータ型の表現
| データ型 | 行LCR表現 | 取得プロセスによって取得される行LCRに存在できるかどうか | 同期取得によって取得される行LCRに存在できるかどうか | ユーザーが構成する行LCRに存在できるかどうか |
|---|---|---|---|---|
|
固定幅 |
|
できる |
できない |
できる |
|
可変幅 |
AL16UTF16キャラクタ・セットの |
できる |
できない |
できない |
|
|
AL16UTF16キャラクタ・セットの |
できる |
できない |
できない |
|
|
|
できる |
できない |
できる |
|
|
|
できる |
できない |
できない |
Oracle Streams環境でのLOBデータ型に関係する行変更の一般的な考慮事項は、次のとおりです。
LOB列に関係する行変更は、複数の行LCRとして取得、伝播および適用される場合があります。
これらの行LCRの評価に使用されるルールは、ルール・セット内のルールが行変更に対応するすべての行LCRをTRUEと評価するか、またはどの行LCRもTRUEと評価しないように、決定的である必要があります。
ここでは、LOB列を構成または処理する場合に満たす必要のある要件、LOB列を含むLCRに対する適用プロセスの動作、およびLOBアセンブリについて説明します。また、LOB列を含むLCRを構成してエンキューする例も示します。
この項の内容は、次のとおりです。
|
関連項目:
|
LOB列を含むLCRを(適用ハンドラを使用せずに)直接適用すると、適用プロセスは次のように動作します。
コマンド・タイプがINSERTまたはUPDATEのLCRにデータを含む新規のLOBがあり、lob_informationがDBMS_LCR.LOB_CHUNKまたはDBMS_LCR.LAST_LOB_CHUNKでない場合は、そのデータが適用されます。
コマンド・タイプがINSERTまたはUPDATEのLCRにデータを含まない新規のLOBがあり、lob_informationがDBMS_LCR.EMPTY_LOBの場合は、空のLOBとして適用されます。
コマンド・タイプがINSERTまたはUPDATEのLCRにデータを含まない新規のLOBがあり、lob_informationがDBMS_LCR.NULL_LOBまたはDBMS_LCR.INLINE_LOBの場合は、NULLとして適用されます。
コマンド・タイプがINSERTまたはUPDATEのLCRに新規のLOBがあり、lob_informationがDBMS_LCR.LOB_CHUNKまたはDBMS_LCR.LAST_LOB_CHUNKの場合は、すべてのLOB値が無視されます。コマンド・タイプがINSERTの場合は、LOBチャンクが続くものとみなされ、列に空のLOBが挿入されます。コマンド・タイプがUPDATEの場合は、LOBチャンクが続くものとみなされ、列の値が無視されます。
コマンド・タイプがUPDATEのLCR内の新規列がすべてLOBで、そのlob_informationがDBMS_LCR.LOB_CHUNKまたはDBMS_LCR.LAST_LOB_CHUNKの場合は、LOBチャンクが続くものとみなされ、更新がスキップされます。
コマンド・タイプがUPDATEまたはDELETEのLCRの場合は、古いLOB値が無視されます。
LOB列を含まない表の行に対して変更を行うと、1つの行LCRが生成されますが、1つ以上のLOB列を含む行に対して変更を行うと、複数の行LCRが生成される場合があります。適用プロセスは、LOB列を含む行LCRを適用ハンドラに送信しない場合、その行LCRを直接適用できます。ただし、Oracle Database 10g リリース2より前のリリースでは、1つの行変更に対して複数のLCRが適切に処理されるように適用ハンドラを構成する必要があったため、LOB列を含む行LCRのカスタム処理は複雑でした。
Oracle Database 10g リリース2以上では、LOBアセンブリによって、取得プロセスで取得されたLOB列を含む行LCRのカスタム処理が簡略化されています。LOBアセンブリを使用すると、LOB列を含む行に対する変更によって生成される複数の取得された行LCRが、1つの行LCRに自動的に結合されます。LOBアセンブリを有効にすると、適用プロセスがこの1つの行LCRをDMLハンドラまたはエラー・ハンドラに渡します。また、LOBアセンブリの実行後は、LOB列値がVARCHAR2またはRAWデータ型値ではなくLOBロケータとして表されます。プロシージャDMLハンドラまたはエラー・ハンドラにLOBアセンブリを有効化するには、DBMS_APPLY_ADM.SET_DML_HANDLERプロシージャでassemble_lobsパラメータをTRUEに設定します。文DMLハンドラに対しては、LOBアセンブリは常に有効化されています。
DMLハンドラまたはエラー・ハンドラに対してassemble_lobsパラメータをFALSEに設定した場合、LOBアセンブリは無効化され、LOB列を含む1行の変更に対して複数の行LCRがハンドラに渡されます。表14-2に、LOBアセンブリを無効化した場合のOracle Streamsの動作を示します。具体的には、LOB列を含む1行に対する変更によって生成され、プロシージャDMLハンドラまたはエラー・ハンドラに渡されるLCRを示します。
表14-2 LOBアセンブリを無効化した場合のOracle Streamsの動作
| 元の行変更 | 最初のLCRのセット | 2番目のLCRのセット | 3番目のLCRのセット | 最後のLCRのセット |
|---|---|---|---|---|
|
|
1つの |
1つ以上の |
1つ以上の |
|
|
|
1つの |
1つ以上の |
1つ以上の |
|
|
|
1つの |
なし |
なし |
なし |
|
|
1つ以上の |
なし |
なし |
なし |
|
|
1つの |
なし |
なし |
なし |
|
|
1つの |
なし |
なし |
なし |
表14-3に、LOBアセンブリを有効化した場合のOracle Streamsの動作を示します。具体的には、LOB列を含む1行に対する変更によって生成され、DMLハンドラまたはエラー・ハンドラに渡される行LCRを示します。
表14-3 LOBアセンブリを有効化した場合のOracle Streamsの動作
| 元の行変更 | 1つのLCR |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOBアセンブリを有効化すると、DMLハンドラまたはエラー・ハンドラによって、行LCRのLOB列が変更されます。DMLハンドラまたはエラー・ハンドラとして指定したPL/SQLプロシージャ内でLOBに対する操作を実行するには、DBMS_LOBパッケージのサブプログラムを使用することをお薦めします。行LCRにNULLのLOB列が含まれている場合、新しいLOBロケータでNULLを置き換える必要があります。EXECUTEメンバー・プロシージャを使用して行LCRを適用する場合は、行LCR用のADD_COLUMN、SET_VALUEおよびSET_VALUESメンバー・プロシージャを使用してLOBに対する変更を行います。
LOBアセンブリを有効化すると、LOBアセンブリによって、永続LCR内の非NULLのLOB列がLOBロケータに変換されます。ただし、LOBアセンブリでは、複数の永続行LCRが1つの行LCRに結合されません。たとえば、永続行LCRの場合、LOBアセンブリでは、INSERT行LCRの後に続く複数のLOB WRITE行LCRは1つのINSERT行LCRに結合されません。
|
関連項目:
|
LOBアセンブリを使用する場合の考慮事項は次のとおりです。
DMLハンドラまたはエラー・ハンドラを使用して、アセンブルされたLOBを複数の宛先データベースで処理するには、LOBアセンブリによって各宛先データベースで個別にLOBをアセンブルする必要があります。
Oracle Database 10g リリース2より前のリリースのOracleが実行されているデータベースで取得された行LCRは、LOBアセンブリでアセンブルできません。
互換レベルが10.2.0より低いOracle Database 10g リリース2以上が実行されているデータベースで取得された行LCRは、LOBアセンブリでアセンブルできません。
適用ハンドラにLOBアセンブリを指定するには、適用ハンドラが実行されているデータベースの互換レベルが10.2.0以上である必要があります。
LONGまたはLONG RAW列を含む表からの行LCRは、LOBアセンブリでアセンブルできません。
DBMS_APPLY_ADMパッケージのSET_ENQUEUE_DESTINATIONおよびSET_EXECUTEプロシージャは、常に元のアセンブルされていない行LCRに実行されます。したがって、LOB列を含む行LCRの場合、行LCRが宛先データベースで適用ハンドラ用に個別にアセンブルされていても、元のアセンブルされていない行LCRがエンキューまたは実行されます。
取得、伝播または適用中に、LOB列を含む行LCRにルールベースの変換が実行された場合、適用ハンドラは変換済の行LCRに実行されます。ソース・データベースにLONGまたはLONG RAW列が存在し、ルールベースの変換で行LCR用のCONVERT_LONG_TO_LOB_CHUNKメンバー・ファンクションを使用してそれらの列がLOBに変換される場合、これらの行LCRに実行される適用ハンドラに対してLOBアセンブリを有効化できます。
行LCRに1つ以上のXMLType列が含まれている場合、DMLハンドラまたはエラー・ハンドラに対してassemble_lobsパラメータがFALSEに設定されていても、行LCRのすべてのXMLType列およびLOB列が常にアセンブルされます。
|
関連項目:
|
この項では、プロシージャDMLハンドラとともにLOBアセンブリを使用する例を示します。この例では、複数のデータベースでoe.production_information表を共有しているが、一部のデータベースのみを会社のオンラインWorld Wide Webカタログに使用している会社について考えます。この会社は各製品の写真をカタログ・データベースに格納する予定ですが、領域を節約するために、カタログ・データベース以外のデータベースには写真を格納しません。
この目標を達成するには、接続先カタログ・データベースのプロシージャDMLハンドラで、データ型BLOBの列photoを、ソース・データベースのproduct_information表に対して実行される各INSERTおよびUPDATEに追加します。ソース・データベースの表にphoto列は含まれません。プロシージャDMLハンドラは、接続先で既存の写真を使用して更新および挿入を実行するように構成されます。また、この会社には、すべてのデータベースのoe.product_information表にproduct_long_descを追加する目標もあります。この表には、簡単な説明を含むproduct_description列がすでに存在します。product_long_desc列のデータ型はCLOBで、詳細な説明が含まれています。詳細な説明は英語で記述されていますが、会社の1つのデータベースを使用して、会社のカタログがスペイン語で表示されます。したがって、適切な言語で詳細な説明が表示されるように、プロシージャDMLハンドラによってproduct_long_desc列が更新されます。
次の手順を実行して、LOBアセンブリを使用して前述の目標を達成するようにプロシージャDMLハンドラを構成します。
次の文を実行すると、photo列が宛先データベースのproduct_information表に追加されます。
ALTER TABLE oe.product_information ADD(photo BLOB);
次の文を実行すると、product_long_desc列が、環境内のすべてのデータベースのproduct_information表に追加されます。
ALTER TABLE oe.product_information ADD(product_long_desc CLOB);
この例では、convert_product_informationプロシージャを作成します。このプロシージャは、プロシージャDMLハンドラ用に使用されます。このプロシージャでは、ユーザーが作成した次のPL/SQLサブプログラムが存在すると想定されています。
get_photoプロシージャ。product_idに基づいてURLまたは表からBLOB形式の写真を取得し、引数として渡されたBLOBロケータを更新します。
get_product_long_descプロシージャ。product_idのIN引数およびproduct_long_descのIN OUT引数を持ち、product_long_descをスペイン語に翻訳するか、または置換用のスペイン語の説明を取得して、product_long_descを更新します。
次のコードを実行すると、convert_product_informationプロシージャが作成されます。
CREATE OR REPLACE PROCEDURE convert_product_information(in_any IN ANYDATA)
IS
lcr SYS.LCR$_ROW_RECORD;
rc PLS_INTEGER;
product_id_anydata ANYDATA;
photo_anydata ANYDATA;
long_desc_anydata ANYDATA;
tmp_photo BLOB;
tmp_product_id NUMBER;
tmp_prod_long_desc CLOB;
tmp_prod_long_desc_src CLOB;
tmp_prod_long_desc_dest CLOB;
t PLS_INTEGER;
BEGIN
-- Access LCR
rc := in_any.GETOBJECT(lcr);
product_id_anydata := lcr.GET_VALUE('OLD', 'PRODUCT_ID');
t := product_id_anydata.GETNUMBER(tmp_product_id);
IF ((lcr.GET_COMMAND_TYPE = 'INSERT') or (lcr.GET_COMMAND_TYPE = 'UPDATE')) THEN
-- If there is no photo column in the lcr then it must be added
photo_anydata := lcr.GET_VALUE('NEW', 'PHOTO');
-- Check if photo has been sent and if so whether it is NULL
IF (photo_anydata is NULL) THEN
tmp_photo := NULL;
ELSE
t := photo_anydata.GETBLOB(tmp_photo);
END IF;
-- If tmp_photo is NULL then a new temporary LOB must be created and
-- updated with the photo if it exists
IF (tmp_photo is NULL) THEN
DBMS_LOB.CREATETEMPORARY(tmp_photo, TRUE);
get_photo(tmp_product_id, tmp_photo);
END IF;
-- If photo column did not exist then it must be added
IF (photo_anydata is NULL) THEN
lcr.ADD_COLUMN('NEW', 'PHOTO', ANYDATA.CONVERTBLOB(tmp_photo));
-- Else the existing photo column must be set to the new photo
ELSE
lcr.SET_VALUE('NEW', 'PHOTO', ANYDATA.CONVERTBLOB(tmp_photo));
END IF;
long_desc_anydata := lcr.GET_VALUE('NEW', 'PRODUCT_LONG_DESC');
IF (long_desc_anydata is NULL) THEN
tmp_prod_long_desc_src := NULL;
ELSE
t := long_desc_anydata.GETCLOB(tmp_prod_long_desc_src);
END IF;
IF (tmp_prod_long_desc_src IS NOT NULL) THEN
get_product_long_desc(tmp_product_id, tmp_prod_long_desc);
END IF;
-- If tmp_prod_long_desc IS NOT NULL, then use it to update the LCR
IF (tmp_prod_long_desc IS NOT NULL) THEN
lcr.SET_VALUE('NEW', 'PRODUCT_LONG_DESC',
ANYDATA.CONVERTCLOB(tmp_prod_long_desc_dest));
END IF;
END IF;
-- DBMS_LOB operations also are executed
-- Inserts and updates invoke all changes
lcr.EXECUTE(TRUE);
END;
/
この手順では、宛先データベースでのINSERT、UPDATEおよびLOB_UPDATE操作用のプロシージャDMLハンドラとしてconvert_product_informationプロシージャを設定します。SET_DML_HANDLERプロシージャを実行するたびに、assemble_lobsパラメータがTRUEに設定されていることに注意してください。
BEGIN
DBMS_APPLY_ADM.SET_DML_HANDLER(
object_name => 'oe.product_information',
object_type => 'TABLE',
operation_name => 'INSERT',
error_handler => FALSE,
user_procedure => 'strmadmin.convert_product_information',
apply_database_link => NULL,
assemble_lobs => TRUE);
DBMS_APPLY_ADM.SET_DML_HANDLER(
object_name => 'oe.product_information',
object_type => 'TABLE',
operation_name => 'UPDATE',
error_handler => FALSE,
user_procedure => 'strmadmin.convert_product_information',
apply_database_link => NULL,
assemble_lobs => TRUE);
DBMS_APPLY_ADM.SET_DML_HANDLER(
object_name => 'oe.product_information',
object_type => 'TABLE',
operation_name => 'LOB_UPDATE',
error_handler => FALSE,
user_procedure => 'strmadmin.convert_product_information',
apply_database_link => NULL,
assemble_lobs => TRUE);
END;
/
oe.product_information表に対してプロシージャDMLハンドラが適切に設定されていることを確認するには、次の問合せを実行します。
COLUMN OBJECT_OWNER HEADING 'Table|Owner' FORMAT A5
COLUMN OBJECT_NAME HEADING 'Table Name' FORMAT A20
COLUMN OPERATION_NAME HEADING 'Operation' FORMAT A10
COLUMN USER_PROCEDURE HEADING 'Handler Procedure' FORMAT A25
COLUMN ASSEMBLE_LOBS HEADING 'LOB Assembly?' FORMAT A15
SELECT OBJECT_OWNER,
OBJECT_NAME,
OPERATION_NAME,
USER_PROCEDURE,
ASSEMBLE_LOBS
FROM DBA_APPLY_DML_HANDLERS;
出力は次のようになります。
Table
Owner Table Name Operation Handler Procedure LOB Assembly?
----- -------------------- ---------- ------------------------- ---------------
OE PRODUCT_INFORMATION INSERT "STRMADMIN"."CONVERT_PROD Y
UCT_INFORMATION"
OE PRODUCT_INFORMATION UPDATE "STRMADMIN"."CONVERT_PROD Y
UCT_INFORMATION"
OE PRODUCT_INFORMATION LOB_UPDATE "STRMADMIN"."CONVERT_PROD Y
UCT_INFORMATION"
正しいプロシージャconvert_product_informationが、表に対する各操作に使用されていることに注意してください。また、各ハンドラでLOBアセンブリが使用されていることにも注意してください。
環境でLOB列を含む行LCRを生成する場合は、そのLCRを構成または処理するときに、次の項に示す要件を満たす必要があります。
|
関連項目: LOBを含むLCRを構成してエンキューする例については、『Oracle Streams拡張例』を参照してください。 |
LOB列を含むLCRを構成する場合、およびLOBアセンブリが無効化されているDMLハンドラまたはエラー・ハンドラでLOB列を処理する場合、次の要件を満たす必要があります。
LOBアセンブリが無効化されているプロシージャDMLハンドラまたはエラー・ハンドラで、行LCR内のLOB列データを変更しないでください。ただし、DMLハンドラまたはエラー・ハンドラで、行LCR内のLOB以外の列を変更することはできます。
特定の操作にのみ起動される適用ハンドラで、LOB列を含む表からのLCRを処理しないでください。たとえば、INSERT操作にのみ起動される適用ハンドラによって、1つ以上のLOB列を含む表からのLCRを処理しないでください。
LCRのLOB列のデータ部分が、VARCHAR2型またはRAW型である必要があります。VARCHAR2はCLOB、RAWはBLOBとして解析されます。
ユーザーが構成する行LCRのLOB列は、BLOBまたは固定幅CLOBのいずれかである必要があります。NCLOB型または可変幅CLOB型のLOB列を含む行LCRは構成できません。
表外のLOBに有効なコマンド・タイプは、LOB WRITE、LOB ERASEおよびLOB TRIMのみです。
LOB WRITE、LOB ERASEおよびLOB TRIMのLCRの場合は、old_valuesコレクションを空またはNULL、new_valuesを空以外にする必要があります。
LOB WRITE LCRとLOB ERASE LCRの場合は、lob_offsetを有効な値にする必要があります。他のすべてのコマンド・タイプの場合は、その列のLOBチャンクが続くものとみなして、lob_offsetをNULLにする必要があります。
LOB ERASE LCRとLOB TRIM LCRの場合は、lob_operation_sizeを有効な値にする必要があります。他のすべてのコマンド・タイプの場合は、lob_operation_sizeをNULLにする必要があります。
LOB TRIMおよびLOB ERASEは、LCRに含まれているLOB列のlob_informationがLAST_LOB_CHUNKに設定されている場合にのみ有効なコマンド・タイプです。
LOB WRITEは、LCRに含まれているLOB列のlob_informationがLAST_LOB_CHUNKまたはLOB_CHUNKに設定されている場合にのみ有効なコマンド・タイプです。
lob_informationがNULL_LOBに設定されているLOBの場合は、列のデータ部分をVARCHAR2型のNULL(CLOBの場合)またはRAW型のNULL(BLOBの場合)にする必要があります。それ以外の場合は、非NULLのインラインLOB列として解析されます。
各LOB WRITE LCR、LOB ERASE LCRおよびLOB TRIM LCRに許容されるのは、1つの新規チャンクを持つ1つのLOB列参照のみです。
LOB ERASE LCRおよびLOB TRIM LCR用の新規LOBチャンクは、ANYDATAにカプセル化されたNULL値にする必要があります。
前述の要件の妥当性チェックは、すべて適用プロセスによって実行されます。前述の要件が満たされない場合、LOB列を含む行LCRは適用プロセスでは適用できず、適用ハンドラでは処理できません。この場合、LCRは同じトランザクション内の他のLCRとともにエラー・キューに移動します。
LOBアセンブリが有効化されているDMLハンドラまたはエラー・ハンドラでLOB列を処理する場合、次の要件を満たす必要があります。
アセンブルされたLOBを含む行LCR内のLOB列には、次の行LCRのメンバー・プロシージャを使用しないでください。
SET_LOB_INFORMATION
SET_LOB_OFFSET
SET_LOB_OPERATION_SIZE
これらのいずれかのプロシージャを行LCR内のLOB列に使用すると、エラーが発生します。
LOBアセンブリで構成した行LCRは、プロシージャDMLハンドラまたはエラー・ハンドラではエンキューできません。ただし、宛先データベースの1つ以上のハンドラにLOBアセンブリが有効化されている場合でも、DBMS_APPLY_ADMパッケージのSET_ENQUEUE_DESTINATIONプロシージャを使用して、LOB列を含む元のアセンブルされていない行LCRをエンキューできます。
前述の要件の妥当性チェックは、すべて適用プロセスによって実行されます。前述の要件が満たされない場合、LOB列を含む行LCRは適用プロセスでは適用できず、適用ハンドラでは処理できません。この場合、LCRは同じトランザクション内の他のLCRとともにエラー・キューに移動します。LOB列を含む行LCRの場合、元のアセンブルされていない行LCRがエラー・キューに置かれます。
|
関連項目:
|
ルールベースの変換でLOB列を含む行LCRを処理する場合、次の要件を満たす必要があります。
カスタム・ルールベースの変換で、行LCR内のLOB列データを変更しないでください。ただし、カスタム・ルールベースの変換で、LOB列を含む行LCR内のLOB以外の列を変更することはできます。
カスタム・ルールベースの変換で行LCRを処理する場合、次の行LCRのメンバー・プロシージャをLOB列に使用することはできません。
ADD_COLUMN
SET_LOB_INFORMATION
SET_LOB_OFFSET
SET_LOB_OPERATION_SIZE
SET_VALUE
SET_VALUES
DBMS_STREAMS_ADMパッケージのADD_COLUMNプロシージャで作成した宣言ルールベースの変換では、LOB列を行LCRに追加できません。
行変更に対応するすべての行LCRが同じ方法で変換されるように、LOB列を含む行LCRで実行されるルールベースの変換ファンクションは決定的である必要があります。
特定の操作にのみ起動されるカスタム・ルールベースの変換で、LOB列を含む表からのLCRを処理しないでください。たとえば、INSERT操作にのみ実行されるカスタム・ルールベースの変換によって、1つ以上のLOB列を含む表からのLCRを処理しないでください。
|
注意: 行LCRにLOB列が含まれる場合、ルールベースの変換は、常に元のアセンブルされていない行LCRに実行されます。 |
|
関連項目:
|
LONGおよびLONG RAWデータ型は、いずれも取得プロセスによって取得される行LCRに存在できますが、これらのデータ型は行LCR内では次のデータ型として表されます。
LONGデータ型は、行LCR内ではVARCHAR2データ型として表されます。
LONG RAWデータ型は、行LCR内ではRAWデータ型として表されます。
LONGまたはLONG RAW列に関係する行変更は、複数のLCRとして取得、伝播および適用される場合があります。環境でLONGまたはLONG RAW列を含むLCRを使用する場合は、LCRのLONGまたはLONG RAW列のデータ部分が、VARCHAR2型またはRAW型である必要があります。VARCHAR2はLONG、RAWはLONG RAWとして解析されます。
Oracle StreamsでLONGまたはLONG RAW列のデータを含む行LCRを処理する場合は、次の要件を満たす必要があります。
カスタム・ルールベースの変換を使用して、LCR内のLONGまたはLONG RAW列のデータを変更しないでください。ただし、ルールベースの変換を使用して、LONGまたはLONG RAW列のデータを含む行LCR内のLONGおよびLONG RAW以外の列を変更することはできます。
LONGまたはLONG RAWデータを含む行LCRを処理するカスタム・ルールベースの変換では、行LCRのSET_VALUEまたはSET_VALUESメンバー・プロシージャは使用しないでください。これらのメンバー・プロシージャを使用すると、ORA-26679エラーが発生します。
行変更に対応するすべてのLCRが同じ方法で変換されるように、LONGまたはLONG RAW列を含むLCRで実行されるルールベースの変換ファンクションは決定的である必要があります。
DBMS_STREAMS_ADMパッケージのADD_COLUMNプロシージャで作成した宣言ルールベースの変換では、LONGまたはLONG RAW列を行LCRに追加できません。
プロシージャDMLハンドラまたはエラー・ハンドラを使用して、LONGまたはLONG RAW列のデータを含む行LCRを処理することはできません。
LONGまたはLONG RAW列を含むLCRの評価に使用されるルールは、ルール・セット内のルールが行変更に対応するすべてのLCRをTRUEと評価するか、またはどのLCRもTRUEと評価しないように、決定的である必要があります。
適用プロセスを使用して、LONGまたはLONG RAW列のデータを含むLCRを宛先キューにエンキューすることはできません。DBMS_APPLY_ADMパッケージのSET_DESTINATION_QUEUEプロシージャを実行すると、指定した適用プロセスのルールを満たすLCRの宛先キューが設定されます。
|
注意: LONGおよびLONG RAWデータ型は、同期取得によって取得される行LCRまたはユーザーが構成する行LCRには存在できません。 |
|
関連項目:
|