ヘッダーをスキップ
Oracle Databaseデータ・カートリッジ開発者ガイド
11gリリース1(11.1)
E05688-02
  目次
目次
索引
索引

戻る
戻る
次へ
次へ
 

6 マルチメディア・データ型での作業

この章では、ラージ・オブジェクトとしてのOracle Databaseに示されているマルチメディア・データ型の動作方法を説明します。LOB型の簡潔な理論的概論を説明し、データ・カートリッジのPL/SQおよびOCI実装による実用的な使用の説明に焦点を絞っています。

この章の内容は、次のとおりです。

カートリッジとマルチメディア・データ型の概要

一部のデータ・カートリッジでは、グラフィック・イメージやサウンド波形などのRAWバイナリ・データ、またはテキストや数値ストリームなどの文字データを大量に処理する必要があります。Oracleは、この種のデータを処理するためのラージ・オブジェクト(LOB)をサポートしています。

LOB内部とBFILEはともに、大量データの処理に大幅な柔軟性を提供します。

LOBに格納されているデータは、LOBと呼ばれます。Oracleサーバーにとって、LOB値は構造化されておらず、問合せできません。LOB値を解凍し、カートリッジ固有の方法で解析する必要があります。

LOBは、Oracle Call Interface(OCI)またはPL/SQLのDBMS_LOBパッケージを使用して操作できます。LOBの各部を操作するファンクション(LOBを格納できるオブジェクト型に対するメソッドなど)を記述できます。


関連項目

LOBの詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。

LOBのDDL

LOB定義には、CREATE TYPEおよびCREATE TABLE文を使用できます。例6-1では、データ型lob_type内のCLOBが指定されます。

例6-1 型のCLOB属性の作成方法

CREATE OR REPLACE TYPE lob_type AS OBJECT (
  id  INTEGER,
  data CLOB );

例6-2では、各行がlob_tableデータのインスタンスであるオブジェクト表lob_tableを作成します。

例6-2 LOBオブジェクト表の作成方法

CREATE TABLE lob_table OF lob_type;

例6-3では、LOB例6-2のようにオブジェクト表に格納するのではなく、標準の表に格納します。

例6-3 表のLOBオブジェクト列の作成方法

CREATE TABLE lob_table1  (
  id  INTEGER,
  b_lob   BLOB,
  c_lob   CLOB,
  nc_lob  NCLOB,
  b_file  BFILE );

表にLOBを作成するときに、LOBの格納、バッファリングおよびキャッシュ・プロパティを設定できます。


関連項目

CREATE TABLEALTER TABLECREATE TYPEおよびALTER TYPE文にLOBを使用する方法の詳細は、『Oracle Database SQL言語リファレンス』および『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。

LOBロケータ

LOBは、他の行データとともに、または行データとは別個に格納できます。格納場所に関係なく、各LOBには実際の位置へのハンドルまたはポインタとして表示できるロケータがあります。LOBを選択すると、LOB値のかわりにLOBロケータが戻されます。

例6-4では、b_lobLOBロケータを選択してPL/SQLローカル変数image1に入れます。

例6-4 LOBロケータの選択およびローカル変数への割当て方法

DECLARE
       image1  BLOB;
       image_no  INTEGER := 101;
BEGIN
       SELECT b_lob  INTO image1 FROM lob_table
                  WHERE key_value = image_no;
             ...
END;

APIファンクションを使用してLOB値を操作する場合は、ロケータを使用してLOBを参照します。例6-5のように、PL/SQLのDBMS_LOBパッケージには、PUT_LINEGETLENGTHなど、LOBの操作に役立つルーチンが含まれています。

例6-5 PUT_LINE and GETLENGTHでのLOBの操作方法

BEGIN
     DBMS_OUTPUT.PUT_LINE('Size of the Image is: ',
                       DBMS_LOB.GETLENGTH(image1));
END;

OCIでは、LOBロケータはOCILobLocator *などのLOBLocatorPointersにマップされます。

この章では、OCIのLOBインタフェースとPL/SQLのDBMS_LOBパッケージの概要について説明します。

BFILEの場合、LOB列には独自の個別ロケータがあり、サーバーのファイル・システムにある外部ファイルに格納されているLOB値を参照します。これは、BFILE列を含む表の2行で同じファイルまたは2つの個別ファイルを参照できることを意味します。PL/SQLまたはOCIプログラムにおけるBFILEロケータ変数の動作は、他の自動変数と同様です。ファイル操作の場合の動作は、ほとんどの従来型プログラム言語の標準I/Oライブラリの一部として使用可能なファイル・ディスクリプタと同様です。


関連項目

  • 『Oracle Call Interfaceプログラマーズ・ガイド』

  • DBMS_LOB APIの詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。


EMPTY_BLOBおよびEMPTY_CLOBファンクション

特殊ファンクションEMPTY_BLOBおよびEMPTY_CLOBをSQL DMLのINSERTまたはUPDATE文に使用すると、NULLまたはNULL以外の内部LOBを空に初期化できます。これらは、Oracle SQL DMLで特殊ファンクションとして使用可能であり、DBMS_LOBパッケージには含まれていません。

OCIまたはDBMS_LOBパッケージを使用して内部LOBに対するデータの書込みを開始する前に、LOB列を非NULLにする必要があります。つまり、空または移入済のLOB値を指すロケータを含む必要があります。BLOB列の値を空に初期化するには、INSERT文のVALUES句にファンクションEMPTY_BLOBを使用します。同様に、CLOBまたはNCLOB列の値は、ファンクションEMPTY_CLOBを使用して初期化できます。ファンクションの構文は次に示します。

例6-6 EMPTY_CLOB()の構文およびEMPTY_CLOB()ファンクション

FUNCTION EMPTY_BLOB() RETURN BLOB;
FUNCTION EMPTY_CLOB() RETURN CLOB;

EMPTY_BLOBBLOB型の空のロケータを戻し、EMPTY_CLOBCLOB型の空のロケータを戻します。これはNCLOBにも使用できます。ファンクションには関連付けられているプログラマはありません。

例外が発生するのは、これらのファンクションをSQL INSERT文のVALUES句のどこかで使用するか、SQL UPDATE文のSET句のソースとして使用した場合です。

例6-7では、SQL DMLを使用したEMPTY_BLOBを示します。

例6-7 SQL DMLでのEMPTY_BLOB()の使用方法

INSERT INTO lob_table VALUES (1001, EMPTY_BLOB(), 'abcde', NULL);
UPDATE lob_table SET c_lob = EMPTY_CLOB() WHERE key_value = 1001;
INSERT INTO lob_table VALUES (1002, NULL, NULL, NULL);

例6-8では、PL/SQLプログラムでのEMPTY_CLOB()の使用方法を示します。

例6-8 PL/SQLプログラムでのEMPTY_CLOB()の使用方法

DECLARE
  lobb         CLOB;
  read_offset  INTEGER;
  read_amount  INTEGER;
  rawbuf       RAW(20);
  charbuf      VARCHAR2(20);
BEGIN
  read_amount := 10; read_offset := 1;
  UPDATE lob_table SET c_lob = EMPTY_CLOB()
  WHERE key_value = 1002 RETURNING c_lob INTO lobb;
  dbms_lob.read(lobb, read_amount, read_offset, charbuf);
  dbms_output.put_line('lobb value: ' || charbuf);
END

OCIによるLOBの操作

OCIには、BLOBCLOBNCLOBおよびBFILEに格納されたデータへのアクセスに使用できるファンクションが組み込まれています。これらのファンクションは表6-1で説明しています。


関連項目

パラメータ、パラメータの型、戻り値およびコード例を含むドキュメントの詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。

表6-1 OCIのLOB操作ファンクションの概要

関数 説明
OCILobAppend()

LOB値を別のLOBに追加します。

OCILobAssign()

あるLOBロケータを別のロケータに割り当てます。

OCILobCharSetForm()

LOBのキャラクタ・セット形式を戻します。

OCILobCharSetId()

LOBのキャラクタ・セットIDを戻します。

OCILobCopy()

LOBの一部を別のLOBにコピーします。

OCILobDisableBuffering()

バッファリング・サブシステムの使用を無効化します。

OCILobEnableBuffering()

LOBデータの以降の読取り操作と書込み操作にLOBバッファリング・サブシステムを使用します。

OCILobErase()

LOBのうち指定されたオフセット以降の部分を消去します。

OCILobFileClose()

オープンBFILEをクローズします。

OCILobFileCloseAll()

オープンBFILEをすべてクローズします。

OCILobFileExists()

BFILEの有無をテストして確認します。

OCILobFileGetName()

BFILEの名前を戻します。

OCILobFileIsOpen()

BFILEがオープンしているかどうかをテストして確認します。

OCILobFileOpen()

BFILEをオープンします。

OCILobFileSetName()

ロケータ内でBFILEの名前を設定します。

OCILobFlushBuffer()

LOBバッファリング・サブシステムに対する変更内容をデータベース(サーバー)にフラッシュします。

OCILobGetLength()

LOBまたはBFILEの長さを戻します。

OCILobIsEqual()

2つのLOBロケータが同じLOBを参照しているかどうかをテストして確認します。

OCILobLoadFromFile()

BFILEデータを内部LOBにロードします。

OCILobLocatorIsInit()

LOBロケータが初期化されているかどうかをテストして確認します。

OCILobLocatorSize()

LOBロケータのサイズを戻します。

OCILobRead()

NULLでないLOBまたはBFILEの指定の部分をバッファに読み取ります。

OCILobTrim()

LOBを切り捨てます。

OCILobWrite()

バッファからLOBにデータを書き込んで既存のデータを上書きします。


表6-2に、LOBアクセスに関するOCIおよびPL/SQL(DBMS_LOBパッケージ)のインタフェースの比較を示します。

表6-2 OCIおよびPL/SQL(DBMS_LOB)インタフェースの比較

OCI(ociap.h) PL/SQL DBMS_LOB (dbmslob.sql)

該当なし

DBMS_LOB.COMPARE()

該当なし

DBMS_LOB.INSTR()

該当なし

DBMS_LOB.SUBSTR()
OCILobAppend()
DBMS_LOB.APPEND()
OCILobAssign()

該当なし[PL/SQL代入演算子を使用]

OCILobCharSetForm()

該当なし

OCILobCharSetId()

該当なし

OCILobCopy()
DBMS_LOB.COPY()
OCILobDisableBuffering()

該当なし

OCILobEnableBuffering()

該当なし

OCILobErase()
DBMS_LOB.ERASE()
OCILobFileClose()
DBMS_LOB.FILECLOSE()
OCILobFileCloseAll()
DBMS_LOB.FILECLOSEALL()
OCILobFileExists()
DBMS_LOB.FILEEXISTS()
OCILobFileGetName()
DBMS_LOB.FILEGETNAME()
OCILobFileIsOpen()
DBMS_LOB.FILEISOPEN()
OCILobFileOpen()
DBMS_LOB.FILEOPEN()
OCILobFileSetName()

該当なし(BFILENAME演算子を使用)

OCILobFlushBuffer()

該当なし

OCILobGetLength()
DBMS_LOB.GETLENGTH()
OCILobIsEqual()

該当なし[PL/SQL等価演算子を使用]

OCILobLoadFromFile
DBMS_LOB.LOADFROMFILE()
OCILobLocatorIsInit

該当なし[常に初期化]

OCILobRead
DBMS_LOB.READ()
OCILobTrim
DBMS_LOB.TRIM()
OCILobWrite
DBMS_LOB.WRITE()

例6-9では、データベースからロケータへのLOBの選択方法を示します。lob_type型には2つの属性、INTEGER型のidおよびCLOB型のdataがあり、lob_type型のlob_table表がすでに存在しているとみなします。

例6-9 データベースからロケータへのLOBの選択方法

/*-----------------------------------------------------------------------*/
/* Select lob locators from a CLOB column                                */
/* We need the 'FOR UPDATE' clause because we need to write to the LOBs. */
/*-----------------------------------------------------------------------*/
static OCIEnv        *envhp;
static OCIServer     *srvhp;
static OCISvcCtx     *svchp;
static OCIError      *errhp;
static OCISession    *authp;
static OCIStmt       *stmthp;
static OCIDefine     *defnp1;
static OCIBind       *bndhp;

sb4 select_locator(int rowind)
{
  sword retval;
  boolean flag;
  int colc = rowind;
  OCILobLocator *clob;
  text  *sqlstmt = (text *)"SELECT DATA FROM LOB_TABLE WHERE ID = :1 FOR UPDATE";

  if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt),
      (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))
  {
    (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n");
    return OCI_ERROR;
  }

  if (OCIStmtBindByPos(stmthp, bndhp, errhp, (ub4) 1, (dvoid *) &colc,
      (sb4) sizeof(colc), SQLT_INT, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0,
      (ub4 *) 0, (ub4) OCI_DEFAULT))
  {
    (void) printf("FAILED: OCIStmtBindByPos()\n");
    return OCI_ERROR;
  }

  if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1, (dvoid *) &clob, (sb4) -1,
      (ub2) SQLT_CLOB, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT))
  {
    (void) printf("FAILED: OCIDefineByPos()\n");
    return OCI_ERROR;
  }

  /* Execute the select and fetch one row */
  if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
      (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT))
  {
    (void) printf("FAILED: OCIStmtExecute() sqlstmt\n");
    report_error();
    return OCI_ERROR;
  }

  /* Now test to see if the LOB locator is initialized */
  retval = OCILobLocatorIsInit(envhp, errhp, clob, &flag);
  if ((retval != OCI_SUCCESS) && (retval != OCI_SUCCESS_WITH_INFO))
  {
    (void) printf("Select_Locator --ERROR: OCILobLocatorIsInit(),
        retval = %d\n", retval);
    report_error();
    checkerr(errhp, retval);
    return OCI_ERROR;
  }

  if (!flag)
  {
    (void) printf("Select_Locator --ERROR: LOB Locator is not initialized.\n");
    return OCI_ERROR;
  }

  return OCI_SUCCESS;
}

サンプル・プログラムpopulate.cでは、OCIを使用してCLOBにディスク上のファイルの内容が移入されます。

DBMS_LOBによるLOBの操作

DBMS_LOBパッケージを使用すると、PL/SQLからLOBを操作できます。表6-3でこのルーチンを説明します。


関連項目

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

表6-3 DBMS_LOBパッケージ・ルーチンの概要

ルーチン 説明
APPEND()

ソースLOBの内容を宛先LOBに追加します。

COPY()

ソースLOBの内容を宛先LOBにコピーします。

ERASE()

すべてまたは一部のLOBを削除します。

LOADFROMFILE()

BFILEデータを内部LOBにロードします。

TRIM()

LOB値を指定に長さまでトリミングします。

WRITE()

指定されたオフセットからLOBにデータを書き込みます。

GETLENGTH

LOB値の長さを取得します。

INSTR()

LOB内のパターンのn番目の出現箇所の照合位置を戻します。

READ()

LOBの指定のオフセット以降からデータを読み取ります。

SUBSTR()

LOB値のうち指定のオフセット以降の部分を戻します。

FILECLOSE()

ファイルI/Oをクローズします。

FILECLOSEALL()

前にオープンされたファイルをすべてクローズします。

FILEEXISTS()

サーバー上でファイルの有無をテストして確認します。

FILEGETNAME()

ディレクトリ別名とファイル名を取得します。

FILEISOPEN()

ファイルが入力のBFILEロケータを使用してオープンされたかどうかをテストして確認します。

FILEOPEN()

ファイルをオープンします。


例6-10では、TRIMプロシージャをコールしてCLOB値を短い長さにトリミングします。lob_type型には2つの属性、INTEGER型のidおよびCLOB型のdataがあり、lob_type型のlob_table表がすでに存在しているとみなします。この例ではCLOBデータを処理するため、DBMS_LOB.TRIMの第2引数(834004)では文字数を指定します。この例でBLOBデータを処理する場合、この引数はバイト数として解析されます。

例6-10 CLOBのトリミング方法

PROCEDURE Trim_Clob IS
        clob_loc  CLOB;
BEGIN
 -- get the LOB Locator
       SELECT data into clob_loc  FROM lob_table
       WHERE id  =  179 FOR UPDATE;
   -- call the TRIM Routine
       DBMS_LOB.TRIM(clob_loc, 834004);
       COMMIT;
END;

外部プロシージャ内のLOB

LOBロケータは、外部プロシージャに引数として渡すことができます。対応するCのファンクションは、OCILobLocator *型の引数を取得します。表6-3に定義されたファンクションは、コール時に次のシグネチャを使用してcルーチン(c_findmin())を起動します。

int c_findmin(OCILobLocator *);

例6-11 PL/SQL外部プロシージャの定義方法

FUNCTION DS_Findmin(data CLOB) RETURN PLS_INTEGER IS EXTERNAL
                   NAME "c_findmin" LIBRARY DS_Lib LANGUAGE C;

このルーチン(c_findmin)は、DS_Libに関連した共有ライブラリにあります。ポインタOCILobLocator *を使用してLOBからデータを取得するには、コールバックを実行してデータベースに再接続する必要があります。

LOBとトリガー

種類に関係なくトリガー内のLOB(:oldまたは:new値)には書き込めません。

標準的なトリガーの場合、:old値は読み取れますが、:new値は読み取れません。INSTEAD OFトリガーの場合は、:old値と:new値を読み取ることができます。

トリガーが定義されている基礎となる表を更新しなくてもBFILE型を更新できるため、OF句にはLOB型の列を指定できません。

OCIファンクションまたはDBMS_LOBパッケージを使用してオブジェクト列のLOB値またはLOB属性を更新する場合、その列または属性を含む表に定義されているトリガーは起動されません。

パフォーマンス向上のためのカッコとしてのOpen/Closeの使用

Open/Closeファンクションを使用すると、一連のLOB操作の開始と終了を示すことができます。これにより、Closeファンクションのコール後に索引の更新のような大規模な操作を実行できます。これは、Openがコールされた後は、LOBが変更されるたびに索引が更新されることはなく、この種の更新はCloseコールまで再開されないことを意味します。

すべてのLOB操作をOpen/Close操作でラップする必要はありませんが、コード・ブロックは次の理由から非常に役立ちます。

Open/Close操作に関するエラーと制限

前にオープンしたLOBをすべてクローズする前にトランザクションをコミットするとエラーになります。トランザクションのロールバック時には、まだオープンされているLOBがすべて破棄されます。つまり、クローズされてトリガーが起動されることはありません。

異なるロケータまたは同じロケータを持つ同じLOBに対して2回Open/Closeを実行するとエラーになります。オープンされていないLOBをクローズするとエラーになります。

例6-12では、loc1がオープンされているLOBを参照し、loc2に割り当てられているとします。以降にLOB値を変更するためにloc2が使用されると、変更はloc1による変更とともにグループ化されます。つまり、LOBマネージャの状態のエントリは1つのみであり、ロケータごとに1つではありません。LOBが(loc1またはloc2を介して)クローズされると、トリガーが起動され、いずれかのロケータを介したLOBの更新がすべてコミットされます。LOBのクローズ後、ユーザーがいずれかのロケータを使用してLOBを変更しようとすると、その操作は暗黙的なOpen()およびClose()Open() ... operation ... Close()として実行されます。読取り一貫性は引き続きロケータごとに維持されることに注意してください。単にロケータではなくLOBがオープンされクローズされることを示しています。作成されるロケータのコピー数に関係なく、LOBのトリガーは最初のCloseコール時に1回のみ起動されます。

例6-12 コード・ブロックのオープンおよびクローズ方法

open (loc1);
loc2 := loc1;
write (loc1);
write (loc2);
open (loc2);  /* error because the LOB is already open */
close (loc1); /* triggers are fired and all LOB updates made prior to this
                 statement by any locator are incorporated in the extensible
                 index */
write (loc2); /* implicit open, write, implicit close */