5.2 BFILEロケータ

BFILEの場合、値はサーバー側のオペレーティング・システム・ファイルに格納されます。つまり、BFILEはデータベースの外部にあります。ファイルを参照するBFILEロケータは、データベース行に格納されます。

オペレーティング・システム・ファイルをBFILEに対応付けるために、まずオペレーティング・システム・ファイルへのフルパス名の別名であるDIRECTORYオブジェクトを作成する必要があります。その後、SQLまたはPL/SQLではBFILENAME関数、OCIではOCILobFileSetName()関数を使用して、BFILE型のインスタンスを初期化できます。このBFILEインスタンスは、次のいずれかの方法で使用できます。
  • 特定のBFILEの必要性が一時的で、作業中のモジュール内で制限されている場合は、このBFILEインスタンスをBFILE型のPL/SQLまたはOCIローカル変数に割り当てることができます。その後、データベース内の列に関連付けることなく、この変数に対してBFILE関連のAPIを使用できます。一時インスタンスに対するBFILE API操作は、サーバーへのラウンドトリップなしでクライアント側で実行されます。
  • INSERT文またはUPDATE文を使用して、BFILE列にBFILEへの永続参照を挿入できます。SQLを使用してBFILEを持つ行を挿入または更新する前に、BFILE変数をNULLまたはDIRECTORYオブジェクト名とファイル名に初期化する必要があります。

    ノート:

    OCISetAttr()関数では、BFILEロケータをNULLに設定できません。OCIにNULL BFILEを挿入するには、バインド値をNULLに設定する必要があります。

同じレコード内に複数のBFILE列が存在する場合や、同じファイルを参照する異なるレコードが存在する場合があります。たとえば、次のUPDATE文は、lob_table内でkey_value = 21を持つ行を持つBFILE列が、key_value = 22を持つ行と同じファイルを参照するように設定します。

UPDATE lob_table SET f_lob = (SELECT f_lob FROM lob_table WHERE key_value = 22) WHERE
      key_value = 21;

オブジェクト内のBFILE

オブジェクトでBFILEを使用している場合は、まずBFILE値を設定し、次にオブジェクトをデータベースにフラッシュする必要があります。したがって、最初にOCIObjectNew()関数をコールし、次にOCILobFileSetName()関数とOCIObjectFlush()関数をそれぞれコールする必要があります。

共有サーバー(マルチスレッド・サーバー)・モードのBFILE

データベースでは、共有サーバー(マルチスレッド・サーバー)・モードでのBFILEデータ型のセッション移行がサポートされません。これは、共有サーバー・セッションでは、BFILE操作がある共有サーバーにバインドされ、あるサーバーから別のサーバーに移行することはできず、オープンしているBFILEインスタンスは、共有サーバーへのコールの終了後も存続できることを意味します。

ディレクトリ・オブジェクトおよびBFILEロケータの作成例

次の各項の例の多くでは、print_media表を使用します。表の構造は次のとおりです。

図5-1 print_media表

print_media表

例5-1 SQLおよびPL/SQLでのBFILEの挿入

conn system/manager

 -- The DBA creates DIRECTORY object and grants READ to the user
create or replace directory MYDIR as '/your/directory/path/here';
GRANT read ON DIRECTORY MYDIR TO pm; 

conn pm/pm

 -- Use BFILENAME to create a BFILE locator for INSERT
INSERT INTO print_media
(product_id, ad_id, ad_composite, ad_sourcetext, ad_graphic)
VALUES
(1, 1, empty_blob(), empty_clob(), BFILENAME('MYDIR','file1.txt')); 

-- After this statement, 2 rows point to the same BFILE
INSERT INTO print_media 
(product_id, ad_id, ad_composite, ad_sourcetext, ad_graphic)  
    select 2, ad_id, ad_composite, ad_sourcetext, ad_graphic from print_media; 

-- Update the 2nd row to point to a different file
UPDATE print_media SET ad_graphic = BFILENAME('MYDIR','file2.txt')  WHERE product_id =2; 

-- Insert a 3rd row with invalid file name
INSERT INTO print_media
(product_id, ad_id, ad_composite, ad_sourcetext, ad_graphic)
VALUES
(3, 3, empty_blob(), empty_clob(), BFILENAME('MYDIR','file_does_not_exist.txt')); 

-- Insert a NULL for BFILE
INSERT INTO print_media
(product_id, ad_id, ad_composite, ad_sourcetext, ad_graphic)
VALUES
(4, 4, empty_blob(), empty_clob(), NULL); 

-- Inserting in PLSQL using a BFILE variable
DECLARE  
    f BFILE;
BEGIN  
    f := BFILENAME('MYDIR','file5.txt');  
    INSERT INTO print_media (product_id, ad_id, ad_composite, ad_sourcetext, ad_graphic)  
    VALUES (5, 5, NULL, NULL, f);
END;
/ 
SELECT product_id, ad_id, ad_graphic FROM print_media ORDER BY 1,2;

例5-2 OCIでのBFILEの挿入

STATIC TEXT *insstmt = "INSERT INTO print_media (product_id, ad_id, ad_graphic) VALUES (:1, :1, :2)";
sword insert_bfile()
{
  OCILobLocator *f = (OCILobLocator *)0;
 
  OCIStmt       *stmthp;
  OCIBind       *bndp1  = (OCIBind *)   0;
  OCIBind       *bndp2  = (OCIBind *)   0;
 
  ub4            id;
 
  CHECK_ERROR (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp,
                              OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0));
 
  /*************** Allocate descriptor ***********************/
  CHECK_ERROR (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &f,
                                  (ub4)OCI_DTYPE_FILE, (size_t) 0,
                                  (dvoid **) 0));
 
 
  /********** Execute insstmt to insert f ********************/
  id = 6;
  CHECK_ERROR (OCILobFileSetName(envhp, errhp, &f,
                                 (text*)"MYDIR", sizeof("MYDIR") -1,
                                 (text*)"file6.txt",
                                 sizeof("file6.txt") -1));
 
  CHECK_ERROR (OCIStmtPrepare(stmthp, errhp, insstmt,
                              (ub4) strlen((char *) insstmt),
                              (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIBindByPos(stmthp, &bndp1, errhp, (ub4) 1, (dvoid *) &id,
                              (sb4) sizeof(id), SQLT_INT, (dvoid *) 0, (ub2 *) 0,
                              (ub2 *)0, (ub4) 0, (ub4*) 0, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIBindByPos(stmthp, &bndp2, errhp, (ub4) 2, (dvoid *) &f4,
                              (sb4) -1, SQLT_BFILE, (dvoid *) 0, (ub2 *) 0,
                              (ub2 *)0, (ub4) 0, (ub4*) 0, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                              (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL,
                              OCI_DEFAULT));
 
  /********** Execute insstmt to insert NULL ********************/
  id = 7;
  CHECK_ERROR (OCIStmtPrepare(stmthp, errhp, insstmt,
                              (ub4) strlen((char *) insstmt),
                              (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIBindByPos(stmthp, &bndp1, errhp, (ub4) 1, (dvoid *) &id,
                              (sb4) sizeof(id), SQLT_INT, (dvoid *) 0, (ub2 *) 0,
                              (ub2 *)0, (ub4) 0, (ub4*) 0, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIBindByPos(stmthp, &bndp2, errhp, (ub4) 2, (dvoid *) NULL,
                              (sb4) -1, SQLT_BFILE, (dvoid *) 0, (ub2 *) 0,
                              (ub2 *)0, (ub4) 0, (ub4*) 0, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                              (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL,
                              OCI_DEFAULT));
 
}