この章では、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.net
ソース・データベースに作成された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.net', 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.net', 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.net', 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.net', 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.NET', 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.NET', 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.NET', 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には存在できません。表11-1に、これらのデータ型のLCR表現、および行LCRに存在できるかどうかを示します。
表11-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の詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。 |
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(10.2)より前のリリースでは、1つの行変更に対して複数のLCRが適切に処理されるように適用ハンドラを構成する必要があったため、LOB列を含む行LCRのカスタム処理は複雑でした。
Oracle Database 10g リリース2(10.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ハンドラまたはエラー・ハンドラに対してassemble_lobs
パラメータをFALSE
に設定した場合、LOBアセンブリは無効化され、LOB列を含む1行の変更に対して複数の行LCRがハンドラに渡されます。表11-2に、LOBアセンブリを無効化した場合のOracle Streamsの動作を示します。具体的には、LOB列を含む1行に対する変更によって生成され、DMLハンドラまたはエラー・ハンドラに渡されるLCRを示します。
表11-2 LOBアセンブリを無効化した場合のOracle Streamsの動作
元の行変更 | 最初のLCRのセット | 2番目のLCRのセット | 3番目のLCRのセット | 最後のLCRのセット |
---|---|---|---|---|
|
1つの |
1つ以上の |
1つ以上の |
|
|
1つの |
1つ以上の |
1つ以上の |
|
|
1つの |
なし |
なし |
なし |
|
1つ以上の |
なし |
なし |
なし |
|
1つの |
なし |
なし |
なし |
|
1つの |
なし |
なし |
なし |
表11-3に、LOBアセンブリを有効化した場合のOracle Streamsの動作を示します。具体的には、LOB列を含む1行に対する変更によって生成され、DMLハンドラまたはエラー・ハンドラに渡される行LCRを示します。
表11-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(10.2)より前のリリースのOracleが実行されているデータベースで取得された行LCRは、LOBアセンブリでアセンブルできません。
互換レベルが10.2.0
より低いOracle Database 10g リリース2(10.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ハンドラを構成します。
手順1: product_information表へのphoto列の追加
次の文を実行すると、photo
列が接続先データベースのproduct_information
表に追加されます。
ALTER TABLE oe.product_information ADD(photo BLOB);
手順2: product_information表へのproduct_long_desc列の追加
次の文を実行すると、product_long_desc
列が、環境内のすべてのデータベースのproduct_information
表に追加されます。
ALTER TABLE oe.product_information ADD(product_long_desc CLOB);
手順3: DMLハンドラ用のPL/SQLプロシージャの作成
この例では、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; /
手順4: 適用プロセスのDMLハンドラの設定
この手順では、接続先データベースでの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; /
手順5: DBA_APPLY_DML_HANDLERSビューの問合せ
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を構成する場合、および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に実行されます。 |
参照:
|
この項の例に、LOBを含むLCRを構成およびエンキューするPL/SQLプロシージャの作成手順を示します。この例は、『Oracle Streams概要および管理』で説明した必要な操作を完了し、Oracle Streams用にデータベースの準備を完了したものと想定しています。
注意: このマニュアルをオンラインで参照している場合、この注意の後にある「BEGINNING OF SCRIPT」の行から次の「END OF SCRIPT」の行までのテキストをテキスト・エディタにコピーし、テキストを編集してご使用の環境用のスクリプトを作成できます。環境内のすべてのデータベースに接続可能なコンピュータで、SQL*Plusを使用してスクリプトを実行します。 |
/************************* BEGINNING OF SCRIPT ******************************
手順1: 出力およびスプール結果の表示
SET
ECHO
ON
を実行し、スクリプトのスプール・ファイルを指定します。このスクリプトの実行後に、スプール・ファイルにエラーがないかをチェックします。
*/ SET ECHO ON SPOOL lob_construct.out /*
手順2: Oracle Streams管理者へのDBMS_STREAMS_MESSAGINGに対するEXECUTE権限の付与
手順8のPL/SQLプロシージャ内でこのパッケージのプロシージャをコールするため、このパッケージに対する明示的なEXECUTE
権限が必要です。
*/ CONNECT / AS SYSDBA; GRANT EXECUTE ON DBMS_STREAMS_MESSAGING TO strmadmin; /*
手順3: Oracle Streams管理者としての接続
*/
SET ECHO ON SET FEEDBACK 1 SET NUMWIDTH 10 SET LINESIZE 80 SET TRIMSPOOL ON SET TAB OFF SET PAGESIZE 100 SET SERVEROUTPUT ON SIZE 100000 CONNECT strmadmin /*
手順4: ANYDATAキューの作成
*/
BEGIN DBMS_STREAMS_ADM.SET_UP_QUEUE( queue_table => 'lobex_queue_table', queue_name => 'lobex_queue'); END; / /*
手順5: 適用プロセスの作成および起動
*/
BEGIN DBMS_APPLY_ADM.CREATE_APPLY( queue_name => 'strmadmin.lobex_queue', apply_name => 'apply_lob', apply_captured => FALSE); END; / BEGIN DBMS_APPLY_ADM.SET_PARAMETER( apply_name => 'apply_lob', parameter => 'disable_on_error', value => 'N'); END; / BEGIN DBMS_APPLY_ADM.START_APPLY( 'apply_lob'); END; / /*
手順6: LOB列を含む表が存在するスキーマの作成
*/
CONNECT system CREATE TABLESPACE lob_user_tbs DATAFILE 'lob_user_tbs.dbf' SIZE 5M REUSE AUTOEXTEND ON MAXSIZE UNLIMITED; ACCEPT password PROMPT 'Enter password for user: ' HIDE CREATE USER lob_user IDENTIFIED BY &password DEFAULT TABLESPACE lob_user_tbs QUOTA UNLIMITED ON lob_user_tbs; GRANT ALTER SESSION, CREATE CLUSTER, CREATE DATABASE LINK, CREATE SEQUENCE, CREATE SESSION, CREATE SYNONYM, CREATE TABLE, CREATE VIEW, CREATE INDEXTYPE, CREATE OPERATOR, CREATE PROCEDURE, CREATE TRIGGER, CREATE TYPE TO lob_user; CONNECT lob_user/lob_user_pw CREATE TABLE with_clob (a NUMBER PRIMARY KEY, c1 CLOB, c2 CLOB, c3 CLOB); CREATE TABLE with_blob (a NUMBER PRIMARY KEY, b BLOB); /*
手順7: Oracle Streams管理者への表に対する必要な権限の付与
次の権限を付与すると、Oracle Streams管理者は、LOBオフセット長を取得し、表にDML操作を実行できるようになります。
*/ GRANT ALL ON with_clob TO strmadmin; GRANT ALL ON with_blob TO strmadmin; COMMIT; /*
手順8: LOBを含むLCRをエンキューするPL/SQLプロシージャの作成
*/
CONNECT strmadmin CREATE OR REPLACE PROCEDURE enq_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 xr_lcr SYS.LCR$_ROW_RECORD; BEGIN xr_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 a row lcr DBMS_STREAMS_MESSAGING.ENQUEUE( queue_name => 'lobex_queue', payload => ANYDATA.ConvertObject(xr_lcr)); END enq_row_lcr; / SHOW ERRORS /*
手順9: CLOBデータをエンキューするdo_enq_clobファンクションの作成
*/
-- Description of each variable: -- src_dbname : Source database name -- tab_owner : Table owner -- tab_name : Table name -- col_name : Name of the CLOB column -- new_vals : SYS.LCR$_ROW_LIST containing primary key and supplementally -- logged colums -- clob_data : CLOB that contains data to be sent -- offset : Offset from which data should be sent, default is 1 -- lsize : Size of data to be sent, default is 0 -- chunk_size : Size used for creating LOB chunks, default is 2048 CREATE OR REPLACE FUNCTION do_enq_clob(src_dbname VARCHAR2, tab_owner VARCHAR2, tab_name VARCHAR2, col_name VARCHAR2, new_vals SYS.LCR$_ROW_LIST, clob_data CLOB, offset NUMBER default 1, lsize NUMBER default 0, chunk_size NUMBER default 2048) RETURN NUMBER IS lob_offset NUMBER; -- maintain lob offset newunit SYS.LCR$_ROW_UNIT; tnewvals SYS.LCR$_ROW_LIST; lob_flag NUMBER; lob_data VARCHAR2(32767); lob_size NUMBER; unit_pos NUMBER; final_size NUMBER; exit_flg BOOLEAN; c_size NUMBER; i NUMBER; BEGIN lob_size := DBMS_LOB.GETLENGTH(clob_data); unit_pos := new_vals.count + 1; tnewvals := new_vals; c_size := chunk_size; i := 0; -- validate parameters IF (unit_pos <= 1) THEN DBMS_OUTPUT.PUT_LINE('Invalid new_vals list'); RETURN 1; END IF; IF (c_size < 1) THEN DBMS_OUTPUT.PUT_LINE('Invalid LOB chunk size'); RETURN 1; END IF; IF (lsize < 0 OR lsize > lob_size) THEN DBMS_OUTPUT.PUT_LINE('Invalid LOB size'); RETURN 1; END IF; IF (offset < 1 OR offset >= lob_size) THEN DBMS_OUTPUT.PUT_LINE('Invalid lob offset'); RETURN 1; ELSE lob_offset := offset; END IF; -- calculate final size IF (lsize = 0) THEN final_size := lob_size; ELSE final_size := lob_offset + lsize; END IF; -- The following output lines are for debugging purposes only. -- DBMS_OUTPUT.PUT_LINE('Final size: ' || final_size); -- DBMS_OUTPUT.PUT_LINE('Lob size: ' || lob_size); IF (final_size < 1 OR final_size > lob_size) THEN DBMS_OUTPUT.PUT_LINE('Invalid lob size'); RETURN 1; END IF; -- expand new_vals list for LOB column tnewvals.extend(); exit_flg := FALSE; -- Enqueue all LOB chunks LOOP -- The following output line is for debugging purposes only. DBMS_OUTPUT.PUT_LINE('About to write chunk#' || i); i := i + 1; -- check if last LOB chunk IF ((lob_offset + c_size) < final_size) THEN lob_flag := DBMS_LCR.LOB_CHUNK; ELSE lob_flag := DBMS_LCR.LAST_LOB_CHUNK; exit_flg := TRUE; -- The following output line is for debugging purposes only. DBMS_OUTPUT.PUT_LINE('Last LOB chunk'); END IF; -- The following output lines are for debugging purposes only. DBMS_OUTPUT.PUT_LINE('lob offset: ' || lob_offset); DBMS_OUTPUT.PUT_LINE('Chunk size: ' || to_char(c_size)); lob_data := DBMS_LOB.SUBSTR(clob_data, c_size, lob_offset); -- create row unit for clob newunit := SYS.LCR$_ROW_UNIT(col_name, ANYDATA.ConvertVarChar2(lob_data), lob_flag, lob_offset, NULL); -- insert new LCR$_ROW_UNIT tnewvals(unit_pos) := newunit; -- enqueue lcr enq_row_lcr( source_dbname => src_dbname, cmd_type => 'LOB WRITE', obj_owner => tab_owner, obj_name => tab_name, old_vals => NULL, new_vals => tnewvals); -- calculate next chunk size lob_offset := lob_offset + c_size; IF ((final_size - lob_offset) < c_size) THEN c_size := final_size - lob_offset + 1; END IF; -- The following output line is for debugging purposes only. DBMS_OUTPUT.PUT_LINE('Next chunk size : ' || TO_CHAR(c_size)); IF (c_size < 1) THEN exit_flg := TRUE; END IF; EXIT WHEN exit_flg; END LOOP; RETURN 0; END do_enq_clob; / SHOW ERRORS /*
手順10: do_enq_clobファンクションを使用したCLOBデータのエンキュー
次の例に示すDBMS_OUTPUT
行は、必要に応じて、デバッグのために使用できます。この行が不要な場合は、コメント・アウトまたは削除できます。
*/ SET SERVEROUTPUT ON SIZE 100000 DECLARE c1_data CLOB; c2_data CLOB; c3_data CLOB; newunit1 SYS.LCR$_ROW_UNIT; newunit2 SYS.LCR$_ROW_UNIT; newunit3 SYS.LCR$_ROW_UNIT; newunit4 SYS.LCR$_ROW_UNIT; newvals SYS.LCR$_ROW_LIST; big_data VARCHAR(22000); n NUMBER; BEGIN -- Create primary key for LCR$_ROW_UNIT newunit1 := SYS.LCR$_ROW_UNIT('A', ANYDATA.ConvertNumber(3), NULL, NULL, NULL); -- Create empty CLOBs newunit2 := sys.lcr$_row_unit('C1', ANYDATA.ConvertVarChar2(NULL), DBMS_LCR.EMPTY_LOB, NULL, NULL); newunit3 := SYS.LCR$_ROW_UNIT('C2', ANYDATA.ConvertVarChar2(NULL), DBMS_LCR.EMPTY_LOB, NULL, NULL); newunit4 := SYS.LCR$_ROW_UNIT('C3', ANYDATA.ConvertVarChar2(NULL), DBMS_LCR.EMPTY_LOB, NULL, NULL); newvals := SYS.LCR$_ROW_LIST(newunit1,newunit2,newunit3,newunit4); -- Perform an insert enq_row_lcr( source_dbname => 'MYDB.NET', cmd_type => 'INSERT', obj_owner => 'LOB_USER', obj_name => 'WITH_CLOB', old_vals => NULL, new_vals => newvals); -- construct clobs big_data := RPAD('Hello World', 1000, '_'); big_data := big_data || '#'; big_data := big_data || big_data || big_data || big_data || big_data; DBMS_LOB.CREATETEMPORARY( lob_loc => c1_data, cache => TRUE); DBMS_LOB.WRITEAPPEND( lob_loc => c1_data, amount => length(big_data), buffer => big_data); big_data := RPAD('1234567890#', 1000, '_'); big_data := big_data || big_data || big_data || big_data; DBMS_LOB.CREATETEMPORARY( lob_loc => c2_data, cache => TRUE); DBMS_LOB.WRITEAPPEND( lob_loc => c2_data, amount => length(big_data), buffer => big_data); big_data := RPAD('ASDFGHJKLQW', 2000, '_'); big_data := big_data || '#'; big_data := big_data || big_data || big_data || big_data || big_data; DBMS_LOB.CREATETEMPORARY( lob_loc => c3_data, cache => TRUE); DBMS_LOB.WRITEAPPEND( lob_loc => c3_data, amount => length(big_data), buffer => big_data); -- pk info newunit1 := SYS.LCR$_ROW_UNIT('A', ANYDATA.ConvertNumber(3), NULL, NULL, NULL); newvals := SYS.LCR$_ROW_LIST(newunit1); -- write c1 clob n := do_enq_clob( src_dbname => 'MYDB.NET', tab_owner => 'LOB_USER', tab_name => 'WITH_CLOB', col_name => 'C1', new_vals => newvals, clob_data => c1_data, offset => 1, chunk_size => 1024); DBMS_OUTPUT.PUT_LINE('n=' || n); -- write c2 clob newvals := SYS.LCR$_ROW_LIST(newunit1); n := do_enq_clob( src_dbname => 'MYDB.NET', tab_owner => 'LOB_USER', tab_name => 'WITH_CLOB', col_name => 'C2', new_vals => newvals, clob_data => c2_data, offset => 1, chunk_size => 2000); DBMS_OUTPUT.PUT_LINE('n=' || n); -- write c3 clob newvals := SYS.LCR$_ROW_LIST(newunit1); n := do_enq_clob(src_dbname=>'MYDB.NET', tab_owner => 'LOB_USER', tab_name => 'WITH_CLOB', col_name => 'C3', new_vals => newvals, clob_data => c3_data, offset => 1, chunk_size => 500); DBMS_OUTPUT.PUT_LINE('n=' || n); COMMIT; END; / /*
手順11: スプール結果のチェック
lob_construct.out
スプール・ファイルをチェックして、このスクリプトの完了後にすべてのアクションが正常に終了していることを確認します。
*/ SET ECHO OFF SPOOL OFF /*************************** END OF SCRIPT ******************************/
スクリプトの実行後に、lob_user.with_clob
表を問い合せて、適用プロセスによって適用された行を表示できます。DBMS_LOCK.SLEEP
文を使用して、エンキューされた行を適用プロセスが適用するための時間のロックを指定します。
CONNECT lob_user/lob_user_pw EXECUTE DBMS_LOCK.SLEEP(10); SELECT a, c1, c2, c3 FROM with_clob ORDER BY a; SELECT a, LENGTH(c1), LENGTH(c2), LENGTH(c3) FROM with_clob ORDER BY a;
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には存在できません。 |
参照:
|