Oracle 8i Application Developer's Guide - Large Objects (LOBs)
Release 8.1.5

A68004-01

Library

Product

Contents

Index

Prev Next

1
Introduction to Working With LOBs

This introductory chapter discusses with the following topics:

The LOB Datatype

Oracle8 regards LOBs as being of two kinds depending on their location with regard to the database -- internal LOBs and external LOBs, also referred to as BFILEs (binary files). Note that when we discuss some aspect of working with LOBs without specifying whether the LOB is internal or external, the characteristic under discussion pertains to both internal and external LOBs.

Internal LOBs are further divided into those that are persistent and those that are temporary.

Internal LOBs

Internal LOBs, as their name suggests, are stored inside database tablespaces in a way that optimizes space and provides efficient access. Internal LOBs use copy semantics and participate in the transactional model of the server. You can recover internal LOBs in the event of transaction or media failure, and any changes to a internal LOB value can be committed or rolled back. In other words, all the ACID properties that pertain to using database objects pertain to using internal LOBs.

Internal LOB Datatypes

There are three SQL datatypes for defining instances of internal LOBs:

External LOBs (BFILEs)

External LOBs (BFILES) are large binary data objects stored in operating system files outside of database tablespaces. These files use reference semantics. Apart from conventional secondary storage devices such as hard disks, BFILEs may also be located on tertiary block storage devices such as CD-ROM, PhotoCDs and DVDs. But note that you cannot locate a single BFILE on more than one device, for instance, striped across a disk array.

The SQL datatype BFILE allows read-only byte stream I/O access to large files existing on the filesystem of the database server. The Oracle Server can access BFILEs provided the underlying server operating system supports a stream-mode access to these operating system (OS) files.


Note:

External LOBs do not participate in transactions. Any support for integrity and durability must be provided by the underlying file system as governed by the operating system.  


External LOB Datatype

There is one external SQL LOB datatype:

Varying-Width Character Data

You can create a table with CLOB/NCLOB columns even if the CHAR/NCHAR database character set is varying width. You can also create a table with a type that has a CLOB attribute irrespective of whether the CHAR database character set is of varying width. However, NCLOBs are not allowed as attributes in object types.

The CLOB/NCLOB value is stored in the database using the 2 byte Unicode character set which is fixed width. The stored Unicode value is translated to the (possibly varying width) character set that you request on either the client or the server. When you insert data into the CLOB/NCLOB, the data input can be in a varying width character set. This varying width character data is implicitly converted into Unicode before the data is stored in the database. Note that all translations to and from Unicode are implicitly performed by Oracle.

You can perform the full gamut of LOB operations on CLOB/NCLOBs (read, write, trim, erase, compare, etc.) All programmatic environments that provide access to CLOBs/NCLOBs work on CLOBs/NCLOBs in databases where the CHAR/NCHAR character set is of varying width. This includes SQL, PL/SQL, OCI, PRO*C, DBMS_LOB, and so on. However, you should take note of the following issue that pertain to specific environments.

DBMS_LOB Package

Regardless of the client-side character set, the offset and amount parameters are always in characters for CLOBs/NCLOBs and in bytes for BLOBs/BFILEs.

OCI

The following decisions only apply to varying-width client-side character sets. For fixed-width client side character sets, the offset and amount parameters are always in characters for CLOBs and NCLOBs and in bytes for BLOBs and BFILEs.

General Rule:

Other Operations:

For all other LOB operations, irrespective of the client-side character set, the amount parameter is in characters for CLOBs and NCLOBs. These include OCILobCopy, OCILobErase, OCILobLoadFromFile, and OCILobTrim. All these operations refer to the amount of LOB data on the server.


For more information, see:

Oracle8i National Language Support Guide  


LOBs in Comparison to LONG and LONG RAW Types

LOBs are similar to LONG and LONG RAW types, but differ in the following ways:

Existing LONG columns can be converted to LOBs using the TO_LOB() function (see "Copy LONG to LOB" in Chapter 2, ". Internal Persistent LOBs"). However note that Oracle8i does not support conversion of LOBs back to LONGs.

LOB Restrictions

The use of LOBs are subject to some restrictions:

Also, LOBs are not allowed in the following places:

DBA Actions Required Prior to Working with LOBs

Set Maximum Number of Open BFILEs

A limited number of BFILEs can be open simultaneously per session. The initialization parameter, SESSION_MAX_OPEN_FILES defines an upper limit on the number of simultaneously open files in a session.

The default value for this parameter is 10. That is, you can open a maximum of 10 files at the same time per session if the default value is utilized. If you want to alter this limit, the database administrator can change the value of this parameter in the init.ora file. For example:

SESSION_MAX_OPEN_FILES=20

If the number of unclosed files exceeds the SESSION_MAX_OPEN_FILES value then you will not be able to open any more files in the session. To close all open files, use the FILECLOSEALL call.

Using SQL DML for Basic Operations on LOBs

SQL DML provides basic operations -- INSERT, UPDATE, SELECT, DELETE -- that let you make changes to the entire values of internal LOBs within the Oracle ORDBMS. To work with parts of internal LOBs, you will need to use one of the interfaces that have been developed to handle more complex requirements.

Oracle8 supports read-only operations on external LOBs. So if you need to update/write to external LOBs, you will have to develop client side applications suited to your needs

Programmatic Environments for Operating on LOBs

Oracle now offers you six different environments for working with LOBs:

Comparison of Six Interfaces

The following chart compares the six LOB interfaces.

Table 1-1 Comparison of Interfaces for working with LOBs
OCI (ociap.h)  DBMS_LOB (dbmslob.sql)  Pro*C & Pro*COBOL  Visual Basic  Java 

N/A  

DBMS_LOB.COMPARE  

N/A  

ORALOB.Compare  

use DBMS_LOB.COMPARE  

N/A  

DBMS_LOB.INSTR  

N/A  

ORALOB.Matchpos  

position  

N/A  

DBMS_LOB.SUBSTR  

N/A  

N/A  

getBytes  

OCILobAppend  

DBMS_LOB.APPEND  

APPEND  

ORALOB.Append  

use length and then putBytes  

OCILobAssign  

N/A [use Pl/SQL assign operator]  

ASSIGN  

ORALOB.Clone  

N/A [use equal sign]  

OCILobCharSetForm  

N/A  

N/A  

N/A  

N/A  

OCILobCharSetId  

N/A  

N/A  

N/A  

N/A  

OCILobClose  

DBMS_LOB.CLOSE  

CLOSE  

N/A  

BLOB/CLOB: uze close() on stream object

BFILE: use DBMS_LOB.CLOSE  

OCILobCopy  

DBMS_LOB.COPY  

COPY  

ORALOB.Copy  

use read and write  

OCILobDisableBuffering  

N/A  

DISABLE BUFFERING  

ORALOB.DisableBuffering  

N/A  

OCILobEnableBuffering  

N/A  

ENABLE BUFFERING  

ORALOB.EnableBuffering  

N/A  

OCILobErase  

DBMS_LOB.ERASE  

ERASE  

ORALOB.Erase  

use DBMS_LOB.ERASE  

OCILobFileClose  

DBMS_LOB.FILECLOSE  

CLOSE  

ORABFILE.Close  

closeFile  

OCILobFileCloseAll  

DBMS_LOB.FILECLOSEALL  

FILE CLOSE ALL  

ORABFILE.CloseAll  

use DBMS_LOB.FILECLOSEALL  

OCILobFileExists  

DBMS_LOB.FILEEXISTS  

DESCRIBE [FILEEXISTS]  

ORABFILE.Exist  

fileExists  

OCILobFileGetChunkSize  

DBMS_LOB.GETCHUNKSIZE  

DESCRIBE [CHUNKSIZE]  

ORALOB.ChunkSize  

N/A  

OCILobFileGetName  

DBMS_LOB.FILEGETNAME  

DESCRIBE [DIRECTORY, FILENAME]  

ORABFILE.DirectoryName

ORABFILE.FileName  

getDirAlias

getName  

OCILobFileIsOpen  

DBMS_LOB.FILEISOPEN  

DESCRIBE [ISOPEN]  

ORABFILE.IsOpen  

use DBMS_LOB.ISOPEN  

OCILobFileOpen  

DBMS_LOB.FILEOPEN  

OPEN  

ORABFILE.Open  

openFile  

OCILobFileSetName  

N/A (use BFILENAME operator)  

FILE SET  

DirectoryName

FileName  

use BFILENAME  

OCILobFlushBuffer  

N/A  

FLUSH BUFFER  

ORALOB.FlushBuffer  

N/A  

OCILobGetLength  

DBMS_LOB.GETLENGTH  

DESCRIBE [LENGTH]  

ORALOB.Size  

length  

OCILobIsEqual  

N/A  

N/A  

N/A  

equals  

OCILobIsOpen  

DBMS_LOB.ISOPEN  

DESCRIBE [ISOPEN]  

ORALOB.IsOpen  

BLOB/CLOB: create stream object

BEILE: use DBMS_LOB.ISOPEN  

OCILobLoadFromFile  

DBMS_LOB.LOADFROMFILE  

LOAD FROM FILE  

ORALOB.CopyFromBfile  

use read and then write  

OCILobLocatorIsInit  

N/A [always initialize]  

N/A  

ORALOB.IsNull  

N/A  

OCILobOpen  

DBMS_LOB.OPEN  

OPEN  

ORALOB.open  

use DBMS_LOB.OPEN  

OCILobRead  

DBMS_LOB.READ  

READ  

ORALOB.Read  

getBytes  

OCILobTrim  

DBMS_LOB.TRIM  

TRIM  

ORALOB.Trim  

use DBMS_LOB.TRIM  

OCILobWrite  

DBMS_LOB.WRITE  

WRITEORALOB.  

Write  

putBytes  

OCILobWriteAppend  

DBMS_LOB.WRITEAPPEND  

WRITE APPEND  

N/A  

use length and then putBytes  

The following subsections describe each of the interfaces in more detail.

Using the DBMS_LOB Package for Working With LOBs

The DBMS_LOB package can be used to read and modify internal LOBs (persistent and temporary) either entirely or in a piece-wise manner. This package can also be used for read operations on BFILEs.


For more information see:

 

As described in more detail below, DBMS_LOB routines work based on LOB locators. For the successful completion of DBMS_LOB routines, you must provide an input locator that represents a LOB that exists in the database tablespaces or external filesystem before you invoke the routine.

For internal LOBs, you must first use SQL DDL to define tables that contain LOB columns, and subsequently SQL DML to initialize or populate the locators in these LOB columns.

For external LOBs, you must define a DIRECTORY object that maps to a valid physical directory containing the external LOBs that you intend to access. Also, these files must exist, and must be set to have read permissions for the Oracle server process. If your operating system uses case-sensitive path names, be sure you specify the directory in the correct format.

Once the LOBs are defined and created, you may then SELECT a LOB locator into a local PL/SQL LOB variable and use this variable as an input parameter to DBMS_LOB for access to the LOB value. Examples provided with each DBMS_LOB routine will illustrate this in the following sections.

The routines that can modify BLOB, CLOB, and NCLOB values are:

Table 1-2 DBMS_LOB Routines that Modify BLOB, CLOB, and NCLOB values
Function/Procedure  Description 

APPEND()  

appends the LOB value to another LOB  

COPY()  

copies a portion of a LOB to another LOB  

ERASE()  

erases part of a LOB, starting at a specified offset  

LOADFROMFILE()  

load BFILE data into an internal LOB  

TRIM()  

trims the LOB value to the specified shorter length  

WRITE()  

writes data to the LOB at a specified offset  

WRITEAPPEND()  

writes data to the end of the LOB  

The routines involved in reading or examining LOB values are:

Table 1-3 DBMS_LOB Routines Involved in Reading or Examining LOB values
Function/Procedure  Description 

COMPARE()  

compares the value of two LOBs  

GETCHUNKSIZE()  

gets the chunk size for reading and writing  

GETLENGTH()  

gets the length of the LOB value  

INSTR()  

returns the matching position of the nth occurrence of the pattern in the LOB  

READ()  

reads data from the LOB starting at the specified offset  

SUBSTR()  

returns part of the LOB value starting at the specified offset  

The following routines have to do with temporary lobs:

Table 1-4 DBMS_LOB Routines that Operate on Temporary LOBs
Function/Procedure  Description 

CREATETEMPORARY()  

creates a temporary LOB  

ISTEMPORARY()  

checks if a LOB locator refers to a temporary LOB  

FREETEMPORARY()  

frees a temporary LOB  

The read-only routines specific to BFILEs are:

Table 1-5 DBMS_LOB Read-Only Routines that are Specific to BFILEs
Function/Procedure  Description 

FILECLOSE()  

closes the file  

FILECLOSEALL()  

closes all previously opened files  

FILEEXISTS()  

checks if the file exists on the server  

FILEGETNAME()  

gets the directory alias and file name  

FILEISOPEN()  

checks if the file was opened using the input BFILE locators  

FILEOPEN()  

opens a file  

The following routines have to do with opening and closing LOBs:

Table 1-6 DBMS_LOB Open and Close Routines
Function/Procedure  Description 

OPEN()  

opens a LOB  

ISOPEN()  

sees if a LOB is open  

CLOSE()  

closes a LOB  

We will describe these routines in greater detail as we explore specific LOB operations (e.g., INSERT a row containing a LOB).

Using the Oracle Call Interface (OCI) with LOBs

You can make changes to an entire internal LOB, or to pieces of the beginning, middle or end of it through the OCI API. You can access both internal and external LOBs for read purposes, and you can also write to internal LOBs.

The OCI includes functions that you can use to access data stored in BLOBs, CLOBs, NCLOBs, and BFILEs. These functions are listed in the tables below, and are discussed in greater detail later in the chapter.

Users who want to read or write data in UCS2 format can set the 'csid' parameter in OCILobRead and OCILobWrite to OCI_UCS2ID. The 'csid' parameter indicates the csid for the buffer parameter. You can set the 'csid' parameter to any character set id. If the csid parameter is set, it will override the NLS_LANG environment variable.


For more information see:

 

The routines that can modify BLOB, CLOB, and NCLOB values are:

Table 1-7 OCI Functions that Modify BLOB, CLOB, and NCLOB values
Function/Procedure  Description 

OCILobAppend()  

appends LOB value to another LOB.  

OCILobCopy()  

copies a portion of a LOB into another LOB.  

OCILobErase()  

erases part of a LOB, starting at a specified offset.  

OCILobLoadFromFile()  

loads BFILE data into an internal LOB.  

OCILobTrim()  

truncates a LOB.  

OCILobWrite()  

writes data from a buffer into a LOB, overwriting existing data.  

OCILobWriteAppend()  

writes data from a buffer to the end of the LOB.  

The routines that read or examine LOB values are:

Table 1-8 OCI Routines that Read or Examine LOB Values
Function/Procedure  Description 

OCILobGetChunkSize()  

gets the size of the Chunk for reading and writing  

OCILobGetLength()  

returns the length of a LOB or a BFILE.  

OCILobRead()  

reads a specified portion of a non-null LOB or a BFILE into a buffer.  

The following routines are have to do with temporary lobs:

Table 1-9 OCI Routines that Operate on Temporary LOBs
Function/Procedure  Description 

OCILobCreateTemporary()  

creates a temporary LOB  

OCILobIsTemporary()  

sees if a temporary LOB exists  

OCILobFreeTemporary()  

frees a temporary LOB  

Read-only routines specific to BFILEs are:

Table 1-10 OCI Read-Only Routines that are Specific to BFILES
Function/Procedure  Description 

OCILobFileClose()  

closes an open BFILE.  

OCILobFileCloseAll()  

closes all open BFILEs.  

OCILobFileExists()  

checks whether a BFILE exists.  

OCILobFileGetName()  

returns the name of a BFILE.  

OCILobFileIsOpen()  

checks whether a BFILE is open.  

OCILobFileOpen()  

opens a BFILE.  

These routines are used for working with LOB locators:

Table 1-11 OCI LOB-Locator Routines
Function/Procedure  Description 

OCILobAssign()  

assigns one LOB locator to another.  

OCILobCharSetForm()  

returns the character set form of a LOB.  

OCILobCharSetId()  

returns the character set ID of a LOB.  

OCILobFileSetName()  

sets the name of a BFILE in a locator.  

OCILobIsEqual()  

checks whether two LOB locators refer to the same LOB.  

OCILobLocatorIsInit()  

checks whether a LOB locator is initialized.  

The following three routines have to do with LOB-buffering:

Table 1-12 OCI LOB-Buffering Routines
Function/Procedure  Description 

OCILobDisableBuffering()  

disables the buffering subsystem use.  

OCILobEnableBuffering()  

uses the LOB buffering subsystem for subsequent reads and writes of LOB data.  

OCILobFlushBuffer()  

flushes changes made to the LOB buffering subsystem to the database (sever)  

The following routines have to do with opening and closing LOBs:

Table 1-13 OCI LOB-Buffering Routines
Function/Procedure  Description 

OCILobOpen()  

opens a LOB  

OCILobIsOpen()  

sees if a LOB is open  

OCILobClose()  

closes a LOB  

A sample main() and LOB procedure

In order to work with the OCI examples in the remainder of the book, you could use a main() like the following. Here, its use with the seeIfLOBIsOpen procedure is shown as an example.

int main(char *argv, int argc)
{
  /* Declare OCI Handles to be used */
  OCIEnv        *envhp;
  OCIServer     *srvhp; 
  OCISvcCtx     *svchp;
  OCIError      *errhp;
  OCISession    *authp;
  OCIStmt       *stmthp;
  OCILobLocator *Lob_loc;

  /* Create and Initialize an OCI Environment: */
  (void) OCIEnvCreate(&envhp, (ub4)OCI_DEFAULT, (dvoid *)0,
                      (dvoid * (*)(dvoid *, size_t)) 0,
                      (dvoid * (*)(dvoid *, dvoid *, size_t))0,
                      (void (*)(dvoid *, dvoid *))0,
                      (size_t) 0, (dvoid **) 0);

  /* Allocate error handle: */
  (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR, 
                        (size_t) 0, (dvoid **) 0);

  /* Allocate server contexts: */
  (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,
                        (size_t) 0, (dvoid **) 0);

  /* Allocate service context: */
  (void) OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,
                        (size_t) 0, (dvoid **) 0);

  /* Attach to the Oracle database:  */
  (void) OCIServerAttach(srvhp, errhp, (text *)"", strlen(""), 0);

  /* Set the server context attribute in the service context: */
  (void) OCIAttrSet ((dvoid *) svchp, OCI_HTYPE_SVCCTX, 
                     (dvoid *)srvhp, (ub4) 0,
                     OCI_ATTR_SERVER, (OCIError *) errhp);

  /* Allocate the session handle: */
  (void) OCIHandleAlloc((dvoid *) envhp, 
                        (dvoid **)&authp, (ub4) OCI_HTYPE_SESSION,
                        (size_t) 0, (dvoid **) 0);
 
  /* Set the username in the session handle:*/
  (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,
                    (dvoid *) "samp", (ub4)4,
                    (ub4) OCI_ATTR_USERNAME, errhp);
  /* Set the password in the session handle: */
  (void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,
                    (dvoid *) "samp", (ub4) 4,
                    (ub4) OCI_ATTR_PASSWORD, errhp);

  /* Authenticate and begin the session: */
  checkerr(errhp, OCISessionBegin (svchp,  errhp, authp, OCI_CRED_RDBMS, 
                                   (ub4) OCI_DEFAULT));

  /* Set the session attribute in the service context: */
  (void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX,
                    (dvoid *) authp, (ub4) 0,
                   (ub4) OCI_ATTR_SESSION, errhp);

  /* ------- At this point a valid session has been created -----------*/
  printf ("user session created \n");

  /* Allocate a statement handle: */
  checkerr(errhp, OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp,
           OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0));

  /* =============  Sample procedure call begins here ===================*/  

  printf ("calling seeIfLOBIsOpen...\n");
  seeIfLOBIsOpen(envhp, errhp, svchp, stmthp);

  return 0;
}

void checkerr(errhp, status)
OCIError *errhp;
sword status;
{
  text errbuf[512];
  sb4 errcode = 0;

  switch (status)
  {
  case OCI_SUCCESS:
    break;
  case OCI_SUCCESS_WITH_INFO:
    (void) printf("Error - OCI_SUCCESS_WITH_INFO\n");
    break;
  case OCI_NEED_DATA:
    (void) printf("Error - OCI_NEED_DATA\n");
    break;
  case OCI_NO_DATA:
    (void) printf("Error - OCI_NODATA\n");
    break;
  case OCI_ERROR:
    (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode,
                        errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
    (void) printf("Error - %.*s\n", 512, errbuf);
    break;
  case OCI_INVALID_HANDLE:
    (void) printf("Error - OCI_INVALID_HANDLE\n");
    break;
  case OCI_STILL_EXECUTING:
    (void) printf("Error - OCI_STILL_EXECUTE\n");
    break;
  case OCI_CONTINUE:
    (void) printf("Error - OCI_CONTINUE\n");
    break;
  default:
    break;
  }
}

/* Select the locator into a locator variable */

sb4 select_frame_locator(Lob_loc, errhp, svchp, stmthp)
OCILobLocator *Lob_loc;
OCIError      *errhp;
OCISvcCtx     *svchp;
OCIStmt       *stmthp;     
{
  text      *sqlstmt = 
                 (text *)"SELECT Frame FROM Multimedia_tab WHERE Clip_ID=1";
  OCIDefine *defnp1;

  checkerr (errhp, OCIStmtPrepare(stmthp, errhp, sqlstmt, 
                                  (ub4)strlen((char *)sqlstmt),
                                  (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
  
  checkerr (errhp, OCIDefineByPos(stmthp, &defnp1, errhp, (ub4) 1,
                                  (dvoid *)&Lob_loc, (sb4)0, 
                                  (ub2) SQLT_BLOB,(dvoid *) 0, 
                                  (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT));

  /* execute the select and fetch one row */
  checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                                 (CONST OCISnapshot*) 0, (OCISnapshot*) 0,  
                                 (ub4) OCI_DEFAULT));
  
  return (0);
}

void seeIfLOBIsOpen(envhp, errhp, svchp, stmthp)
OCIEnv    *envhp;
OCIError  *errhp;
OCISvcCtx *svchp;
OCIStmt   *stmthp;
{
  OCILobLocator *Lob_loc;
  int isOpen;

  /* allocate locator resources */
  (void) OCIDescriptorAlloc((dvoid *)envhp, (dvoid **)&Lob_loc,
                            (ub4)OCI_DTYPE_LOB, (size_t)0, (dvoid **)0);

  /* Select the locator */
  (void)select_frame_locator(Lob_loc, errhp, svchp, stmthp);
  
  /* See if the LOB is Open */
  checkerr (errhp, OCILobIsOpen(svchp, errhp, Lob_loc, &isOpen));
 
  if (isOpen)
  {
    printf("  Lob is Open\n");
    /* ... Processing given that the LOB has already been Opened */
  }
  else
  {
    printf("  Lob is not Open\n");
    /* ... Processing given that the LOB has not been Opened */
  }

  /* Free resources held by the locators*/
  (void) OCIDescriptorFree((dvoid *) Lob_loc, (ub4) OCI_DTYPE_LOB);
  
  return;
}

Using C++ (Pro*C/C++) to Work with LOBs

You can make changes to an entire internal LOB, or to pieces of the beginning, middle or end of it by using embedded SQL. You can access both internal and external LOBs for read purposes, and you can also write to internal LOBs.

Embedded SQL statements allow you to access data stored in BLOBs, CLOBs, NCLOBs, and BFILEs. These statements are listed in the tables below, and are discussed in greater detail later in the chapter.


For more information see:

 

Unlike locators in PL/SQL, locators in Pro*C/C++ are mapped to locator pointers which are then used to refer to the LOB or BFILE value. For the successful completion of an embedded SQL LOB statement you must provide an allocated input locator pointer that represents a LOB that exists in the database tablespaces or external file system before you execute the statement.

Once a locator pointer has been allocated, you may then SELECT a LOB locator into a LOB locator pointer variable and use that variable in an embedded SQL LOB statement to access and manipulate the LOB value. Examples provided with each embedded SQL LOB statement will illustrate this in the following sections.

The statements that can modify BLOB, CLOB, and NCLOB values are:

Table 1-14 Embedded SQL Statements that Modify BLOB, CLOB, and NCLOB values
Statement  Description 

APPEND  

appends a LOB value to another LOB.  

COPY  

copies all or a portion of a LOB into another LOB.  

ERASE  

erases part of a LOB, starting at a specified offset.  

LOAD FROM FILE  

loads BFILE data into an internal LOB at a specified offset.  

TRIM  

truncates a LOB.  

WRITE  

writes data from a buffer into a LOB at a specified offset.  

WRITE APPEND  

writes data from a buffer into a LOB at the end of the LOB.  

The statements that read or examine LOB values are:

Table 1-15 Embedded SQL Statements that Read or Examine LOB Values
Statement  Description 

DESCRIBE [CHUNKSIZE]  

gets the size of the Chunk for writing.  

DESCRIBE [LENGTH]  

returns the length of a LOB or a BFILE.  

READ  

reads a specified portion of a non-null LOB or a BFILE into a buffer.  

The statements that deal with temporary LOBs are:

Table 1-16 Embedded SQL Statements that Operate on Temporary LOBs
Statement  Description 

CREATE TEMPORARY  

creates a temporary LOB.  

DESCRIBE [ISTEMPORARY]  

sees if a LOB locator refers to a temporary LOB.  

FREE TEMPORARY  

frees a temporary LOB.  

The statements specific to BFILEs are:

Table 1-17 Embedded SQL Statements that are Specific to BFILES
Statement  Description 

FILE CLOSE ALL  

closes all open BFILEs.  

DESCRIBE [FILEEXISTS]  

checks whether a BFILE exists.  

DESCRIBE [DIRECTORY, FILENAME]  

returns the directory alias and/or filename of a BFILE.  

These statements are used for working with LOB locators:

Table 1-18 LOB Locator Embedded SQL Statements
Statement  Description 

ASSIGN  

assigns one LOB locator to another.  

FILE SET  

sets the directory alias and filename of a BFILE in a locator.  

The following three statements have to do with the LOB Buffering Subsystem:

Table 1-19 LOB Buffering Subsystem Embedded SQL statements
Statement  Description 

DISABLE BUFFERING  

disables the use of the buffering subsystem.  

ENABLE BUFFERING  

uses the LOB buffering subsystem for subsequent reads and writes of LOB data.  

FLUSH BUFFER  

flushes changes made to the LOB buffering subsystem to the database (server)  

The following statements have to do with opening and closing LOBs and BFILEs:

Table 1-20 Embedded SQL Statements for Opening and CLosing LOBs and BFILEs
Statement  Description 

OPEN  

opens a LOB or BFILE.  

DESCRIBE [ISOPEN]  

sees if a LOB or BFILE is open.  

CLOSE  

closes a LOB or BFILE.  

Using COBOL (Pro*COBOL) to Work with LOBs

You can make changes to an entire internal LOB, or to pieces of the beginning, middle or end of it by using embedded SQL. You can access both internal and external LOBs for read purposes, and you can also write to internal LOBs.

Embedded SQL statements allow you to access data stored in BLOBs, CLOBs, NCLOBs, and BFILEs. These statements are listed in the tables below, and are discussed in greater detail later in the chapter.

Unlike locators in PL/SQL, locators in Pro*COBOL are mapped to locator pointers which are then used to refer to the LOB or BFILE value. For the successful completion of an embedded SQL LOB statement you must provide an allocated input locator pointer that represents a LOB that exists in the database tablespaces or external file system before you execute the statement.

Once a locator pointer has been allocated, you may then SELECT a LOB locator into a LOB locator pointer variable and use that variable in an embedded SQL LOB statement to access and manipulate the LOB value. Examples provided with each embedded SQL LOB statement will illustrate this in the following sections.

In cases in which the Pro*COBOL interface does not supply the required functionality, you can call the OCI via C. We do not provide an example because such programs are operating system dependent.


For more information see:

 

The statements that can modify BLOB, CLOB, and NCLOB values are:

Table 1-21 Embedded SQL Statements that Modify BLOB, CLOB, and NCLOB values
Statement  Description 

APPEND  

appends a LOB value to another LOB.  

COPY  

copies all or a portion of a LOB into another LOB.  

ERASE  

erases part of a LOB, starting at a specified offset.  

LOAD FROM FILE  

loads BFILE data into an internal LOB at a specified offset.  

TRIM  

truncates a LOB.  

WRITE  

writes data from a buffer into a LOB at a specified offset.  

WRITE APPEND  

writes data from a buffer into a LOB at the end of the LOB.  

The statements that read or examine LOB values are:

Table 1-22 Embedded SQL Statements that Read or Examine LOB Values
Statement  Description 

DESCRIBE [CHUNKSIZE]  

gets the size of the Chunk for writing.  

DESCRIBE [LENGTH]  

returns the length of a LOB or a BFILE.  

READ  

reads a specified portion of a non-null LOB or a BFILE into a buffer.  

The statements that deal with temporary LOBs are:

Table 1-23 Embedded SQL Statements that Operate on Temporary LOBs
Statement  Description 

CREATE TEMPORARY  

creates a temporary LOB.  

DESCRIBE [ISTEMPORARY]  

sees if a LOB locator refers to a temporary LOB.  

FREE TEMPORARY  

frees a temporary LOB.  

The statements specific to BFILEs are:

Table 1-24 Embedded SQL Statements that are Specific to BFILES
Statement  Description 

FILE CLOSE ALL  

closes all open BFILEs.  

DESCRIBE [FILEEXISTS]  

checks whether a BFILE exists.  

DESCRIBE [DIRECTORY, FILENAME]  

returns the directory alias and/or filename of a BFILE.  

These statements are used for working with LOB locators:

Table 1-25 LOB Locator Embedded SQL Statements
Statement  Description 

ASSIGN  

assigns one LOB locator to another.  

FILE SET  

sets the directory alias and filename of a BFILE in a locator.  

The following three statements have to do with the LOB Buffering Subsystem:

Table 1-26 LOB Buffering Subsystem Embedded SQL statements
Statement  Description 

DISABLE BUFFERING  

disables the use of the buffering subsystem.  

ENABLE BUFFERING  

uses the LOB buffering subsystem for subsequent reads and writes of LOB data.  

FLUSH BUFFER  

flushes changes made to the LOB buffering subsystem to the database (server)  

The following statements have to do with opening and closing LOBs and BFILEs:

Table 1-27 Embedded SQL Statements for Opening and CLosing LOBs and BFILEs
Statement  Description 

OPEN  

opens a LOB or BFILE.  

DESCRIBE [ISOPEN]  

sees if a LOB or BFILE is open.  

CLOSE  

closes a LOB or BFILE.  

Using Visual Basic (OO4O) to Work with LOBs

You can make changes to an entire internal LOB, or to pieces of the beginning, middle or end of it via the OO4O API. Specifically, you employ the OraBlob, OraClob and OraBFile objects. You can access both internal and external LOBs for read purposes, and you can also write to internal LOBs.

The OraBlob, OraClob interfaces in OO4O provides methods for performing operations on large objects in the database including BLOB, CLOB and NCLOB data types. The OraBFile interface provides methods for performing operations on BFILE data in the database. These interfaces (OraBlob, OraClob, OraBFile) encapsulate LOB locators, so the user does not deal with locators but instead uses the methods and properties provided to perform operations and get state information.

OraMyBFile refers to the locator obtained from a PL/SQL "OUT" parameter as a result of executing a PL/SQL procedure (either by doing an OraDatabase.ExecuteSQL or by using the OraSqlStmt object). Note that an OraConnect.BeginTrans has been called since the locator became invalid after the COMMIT.

When OraBlob, OraClob objects are retrieved as a part of a dynaset, these objects represent LOB locators of the dynaset current row. If the dynaset current row changes due to move operation, OraBlob, OraClob objects will represent LOB locator for the new current row. In order to retain the LOB locator of the OraBlob, OraClob object independent of the dynaset move operation, use the Clone method. This method returns the OraBlob and OraClob object. One could also use these objects as PL/SQL bind parameters. Here is an example which shows both types of usage. The functions and samples are explained in greater detail as part of the reference documentation.

Dim OraDyn as OraDynaset, OraSound1 as OraBLOB, OraSoundClone as OraBlob, 
OraMyBfile as OraBFile

OraConnection.BeginTrans
set OraDyn = OraDb.CreateDynaset("select * from Multimedia_tab order by clip_
id", ORADYN_DEFAULT)
set OraSound1 = OraDyn.Fields("Sound").value
set OraSoundClone = OraSound1

OraParameters.Add "id", 1,ORAPARAM_INPUT
OraParameters.Add "mybfile", Empty,ORAPARAM_OUTPUT
OraParameters("mybfile").ServerType = ORATYPE_BFILE

OraDatabase.ExecuteSQL ("begin  GetBFile(:id, :mybfile ") end")

Set OraMyBFile = OraParameters("mybfile").value
'Go to Next row
OraDyn.MoveNext

OraDyn.Edit
'Lets update OraSound1 data with that from the BFILE
OraSound1.CopyFromBFile  OraMyBFile
OraDyn.Update

OraDyn.MoveNext
'Go to Next row
OraDyn.Edit
'Lets update OraSound1 by appending with LOB data from 1st row represenetd by 
'OraSoundClone
OraSound1.Append  OraSoundClone
OraDyn.Update

OraConnection.CommitTrans

In the above example OraSound1 represents the locator for the current row in the dynaset where as OraSoundClone represents the locator for the 1st row. A change in the current row (say a OraDyn.MoveNext) will mean that OraSound1 will actually represent locator for the 2nd row whereas OraSoundClone will represent the locator in the 1st row (OraSoundClone only refers the locator for the 1st row irrespective of any OraDyn row navigation).

OraMyBFile refers to the locator got an PL/SQL "OUT" parameter as a result of executing a PL/SQL procedure (either by doing an OraDatabase.ExecuteSQL or by using the OraSqlStmt object). Note that an OraConnect.BeginTrans has been called since with a database "COMMIT" the locator becomes invalid.

OO4O includes methods and properties that you can use to access data stored in BLOBs, CLOBs, NCLOBs, and BFILEs. These methods and properties are listed in the tables below, and are discussed in greater detail later in the chapter.


See Also:

OO4O online help for detailed information including parameters, parameter types, return values, and example code.  


The routines that can modify BLOB, CLOB, and NCLOB values are:

Table 1-28 OO4O Methods That Modify BLOB, CLOB, and NCLOB Values
Function/Procedure  Description 

OraBlob.Append, OraClob.Append  

appends LOB value to another LOB.  

OraBlob.Copy, OraClob.Copy  

copies a portion of a LOB into another LOB.  

OraBlob.Erase, OraClob.Erase  

erases part of a LOB, starting at a specified offset.  

OraBlob.CopyFromBFile, OraClob.CopyFromBFile  

loads BFILE data into an internal LOB.  

OraBlob.Trim, OraClob.Trim  

truncates a LOB.  

OraBlob.CopyFromFile, OraClob.CopyFromFile  

writes data from a file to a LOB  

OraBlob.Write, OraClob.Write  

writes data from a file to a LOB  

The routines that read or examine LOB values are:

Table 1-29 Oo4o Methods that Read or Examine LOB Values
Function/Procedure  Description 

OraBlob.Read, OraClob.Read, OraBFile.Read  

reads a specified portion of a non-null LOB into a buffer  

OraBlob.CopyToFile, OraClob.CopyToFile  

reads a specified portion of a non-null LOB to a file.  

The following methods have to do with opening and closing LOBs:

Table 1-30 OO4O Methods for Operating on BFILEs
Methods  Description 

OraBFile.Open  

opens BFILE.  

OraBFile.Close  

closes BFILE.  

The following methods have to do with LOB-buffering:

Table 1-31 OO4O LOB-Buffering methods
Function/Procedure  Description 

OraBlob.FlushBuffer, OraClob.FlushBuffer  

flushes changes made to the LOB buffering subsystem to the database (sever)  

OraBlob.EnableBuffering

OraClob.EnableBuffering  

Enables buffering of LOB operations  

OraBlob.DisableBuffering

OraClob.DisableBuffering  

Disables buffering of LOB operations  

Table 1-32 OO4O LOB- properties
Property  Description 

IsNull (Read)  

indicates when a LOB is Null  

PollingAmount(Read/Write)  

Get/Set the total amount for Read/Write polling operation  

Offset(Read/Write)  

Get/Set the offset for Read/Write operation. By default, it is set to 1.  

Status(Read)  

Returns the polling status.Possible values are

ORALOB_NEED_DATA There is more data to be read/written

ORALOB_NO_DATA There is no more data to be read/written

ORALOB_SUCCESS LOB data read/written successfully  

Size(Read)  

Returns the length of the LOB data  

Methods specific to BFILEs are:

Table 1-33 OO4O Read-Only methods that are Specific to BFILES
Methods  Description 

OraBFile.Close  

closes an open BFILE.  

OraBFile.CloseAll  

closes all open BFILEs.  

OraBFile.Open  

opens a BFILE.  

OraBFile.IsOpen  

determine if a BFILE is open  

Table 1-34 OO4O Properties that are Specific to BFILES
Properties  Description 

OraBFile.DirectoryName  

gets/Sets the server side directory alias name.  

OraBFile.FileName(Read/Write)  

gets/Sets the server side filename.

 

OraBFile.Exists  

checks whether a BFILE exists.  

Using Java (JDBC) to Work with LOBs

You can make changes to an entire internal LOB, or to pieces of the beginning, middle or end of an internal LOB in Java by means of the JDBC API via the Oracle.sql.BLOB and Oracle.sql.CLOB objects. These objects also implement the java.sql.Blob and java.sql.Clob interfaces according to the JDBC 2.0 specification. With this implementation, an Oracle.sql.BLOB can be used wherever a java.sql.Blob is expected and an Oracle.sql.CLOB can be used wherever a java.sql.Clob is expected.

The JDBC interface will let you access both internal and external LOBs for read purposes, and you can also write to internal LOBs.

The BLOB and CLOB classes in JDBC provide methods for performing operations on large objects in the database including BLOB, CLOB and NCLOB data types. The BFILE class provides methods for performing operations on BFILE data in the database. These classes (BLOB, CLOB, BFILE) encapsulate LOB locators, so the user does not deal with locators but instead uses the methods and properties provided to perform operations and get state information. Any of Oracle's LOB functionality not provided by these classes can be accessed by a call to the DBMS_LOB PL/SQL package. This technique is used repeatedly in the examples throughout the book.

You can get a reference to any of the above LOBs either as a column of an OracleResultSet or as an "OUT" type PL/SQL parameter from an OraclePreparedStatement. When BLOB and CLOB objects are retrieved as a part of aN OracleResultSet, these objects represent LOB locators of the currently selected row. If the current row changes due to a move operation (for example, rset.next()), the retrieved locator still refers to the original LOB row. In order to retrieve the locator for the most current row, you must call getXXXX() on the OracleResultSet each time a move operation is made (where XXXX is a BLOB, CLOB or BFILE).


For more information see:

 

oracle.sql.BLOB methods for modifying values:

Table 1-35 oracle.sql.BLOB Methods for Modifying Values
Function/Procedure  Description 

int putBytes(long, byte[])  

inserts the byte array into the LOB, starting at the given offset  

oracle.sql.BLOB methods for reading or examining values:

Table 1-36 oracle.sql.BLOB Methods for Reading or Examining Values
Function/Procedure  Description 

byte[] getBytes(long, int)  

gets the contents of the LOB as an array of bytes, given an offset  

long position(byte[], long)  

finds the given byte array within the LOB, given an offset  

long position(oracle.jdbc2.Blob, long)  

finds the given BLOB within the LOB  

public boolean equals(java.lang.Object)  

compares this LOB with another  

public long length()  

returns the length of the LOB  

public int getChunkSize()  

returns the ChunkSize of the LOB  

oracle.sql.BLOB LOB-buffering methods and properties:

Table 1-37 oracle.sql.BLOB LOB-Buffering Methods and Properties
Function/Procedure  Description 

public java.io.InputStream getBinaryStream())  

streams the LOB as a binary stream  

public java.io.OutputStream getBinaryOutputStream()  

writes to LOB as a binary stream  

oracle.sql.CLOB methods for modifying values

Table 1-38 oracle.sql.CLOB Methods for Modifying Values
Function/Procedure  Description 

int putString(long, java.lang.String)  

inserts the string into the LOB, starting at the given offset  

int putChars(long, char[])  

inserts the character array into the LOB, starting at the given offset  

oracle.sql.CLOB methods for reading or examining values:

Table 1-39 oracle.sql.CLOB Methods for Reading or Examining Values
Function/Procedure  Description 

byte[] getBytes()  

gets the contents of the LOB as an array of bytes  

java.lang.String getSubString(long, int)  

returns a substring of the LOB as a string  

int getChars(long, int, char[])  

reads a subset of the LOB into a character array  

long position(java.lang.String, long)  

finds the given String within the LOB, given an offset  

long position(oracle.jdbc2.Clob, long)  

finds the given CLOB within the LOB, given an offset  

boolean equals(java.lang.Object)  

compares this LOB with another  

long length()  

returns the length of the LOB  

int getChunkSize()  

returns the ChunkSize of the LOB  

oracle.sql.CLOB LOB-buffering methods and properties:

Table 1-40 oracle.sql.CLOB LOB-Buffering Methods and Properties
Function/Procedure  Description 

java.io.InputStream getAsciiStream()  

streams the LOB as an ASCII stream  

java.io.InputStream getStream()  

streams the LOB as a byte array  

java.io.OutputStream getAsciiOutputStream()  

writes to the LOB as an ASCII stream  

java.io.Reader getCharacterStream()  

streams the LOB as a character stream  

java.io.Writer getCharacterOutputStream()  

writes to LOB as a character stream  

oracle.sql.BFILE methods for reading or examining values

Table 1-41 oracle.sql.BFILE Methods for reading or Examining Values
Function/Procedure  Description 

byte[] getBytes()  

gets the contents of the LOB as an array of bytes  

byte[] getBytes(long, int)  

gets the contents of the LOB as an array of bytes, given an offset  

int getBytes(long, int, byte[])  

reads a subset of the LOB into a byte array  

long position(oracle.sql.BFILE, long)  

finds the given BFILE contents within the LOB, given an offset  

long position(byte[], long)  

finds the given byte array within the LOB, given an offset  

boolean equals(java.lang.Object)  

compares this LOB with another  

long length()  

returns the length of the LOB  

boolean fileExists()  

checks if the OS file referenced by this BFILE exists  

public void openFile()  

opens the OS file referenced by this BFILE  

public void closeFile()  

closes the OS file referenced by this BFILE  

public boolean isFileOpen()  

checks if this BFILE is already open  

public java.lang.String getDirAlias()  

gets the directory alias for this BFILE  

public java.lang.String getName()  

gets the file name referenced by this BFILE  

oracle.sql.BFILE methods for LOB-buffering methods and properties:

Table 1-42 oracle.sql.CLOB Methods for Modifying Values
Function/Procedure  Description 

public java.io.InputStream getBinaryStream()  

streams the LOB as a binary stream  

public java.io.InputStream getStream()  

streams the LOB as a byte array  

An Example Application

Oracle8 supports LOBs, large objects which can hold up to 4 gigabytes of binary or character data. What does this mean for you, the application developer?

Consider the following hypothetical application:

The Multimedia Content-Collection System

Multimedia data is used in an increasing variety of media channels -- film, television, webpages, and CD-ROM being the most prevalent. The media experiences having to do with these different channels vary in many respects (interactivity, physical environment, the structure of information, to name a few). Yet despite these differences, there is often considerable similarity in the multimedia authoring process, especially with regard to assembling content.

Figure 1-1 The Multimedia Authoring Process


For instance, a television station that creates complex documentaries, an advertising agency that produces advertisements for television, and a software production house that specializes in interactive games for the web could all make good use of a database management system for collecting and organizing the multimedia data. Presumably, they each have sophisticated editing software for composing these elements into their specific products, but the complexity of such projects creates a need for a pre-composition application for organizing the multimedia elements into appropriate groups.

Taking our lead from movie-making, our hypothetical application for collecting content uses the clip as its basic unit of organization. Any clip is able to include one or more of the following media types:

Since this is a pre-editing application, the precise relationship of elements within a clip (such as the synchronization of voice-over audio with a photograph) and between clips (such as the sequence of clips) is not defined.

The application should allow multiple editors working simultaneously to store, retrieve and manipulate the different kinds of multimedia data. We assume that some material is gathered from in-house databases. At the same time, it should also be possible to purchase and download data from professional services.

Note: The Example is Only An Example

Our mission in this chapter is not to create this real-life application, but to describe everything you need to know about working with LOBs. Consequently, we only implement the application sufficiently to demonstrate the technology. For example, we deal with only a limited number of multimedia types. We make no attempt to create the client-side applications for manipulating the LOBs. And we do not deal with deployment issues such as, the fact that you should implement disk striping of LOB files, if possible, for best performance.

Applying an Object-Relational Design to the Application

Figure 1-2 Schema Plan for Table MULTIMEDIA_TAB

The Structure of the Multimedia_tab Table

Figure 1-3 Schema Plan for Table MULTIMEDIA_TAB


Figure 1-4 Schema Design for Inclusion of VOICED_REF Reference


Figure 1-5 Schema Design for Inclusion of a Nested Table INTERVIEWSEGMENTS_TAB


Figure 1-6 Schema Design for Inclusion of a Column Object MAP_OBJ


The Most Basic Operation: Getting and Using the LOB Locator

LOB Value and Locators

Inline storage of the LOB value

Data stored in a LOB is termed the LOB's value. The value of an internal LOB may or may not be stored inline with the other row data. If the internal LOB value is less than approximately 4000 bytes, then the value is stored inline; otherwise it is stored outside the row. Since LOBs are intended to be large objects, inline storage will only be relevant if your application mixes small and large LOBs.

As mentioned below ("ENABLE | DISABLE STORAGE IN ROW" on page 1-45), the LOB value is automatically moved out of the row once it extends beyond approximately 4000 bytes.

LOB locators

Regardless of where the value of the internal LOB is stored, a locator is stored in the row. You can think of a LOB locator as a pointer to the actual location of the LOB value. A LOB locator is a locator to an internal LOB while a BFILE locator is a locator to an external LOB. When the term locator is used without an identifying prefix term, it refers to both LOB locators and BFILE locators.

Internal LOB Locators

For internal LOBs, the LOB column stores a locator to the LOB's value which is stored in a database tablespace. Each LOB column/attribute for a given row has its own distinct LOB locator and copy of the LOB value stored in the database tablespace.

LOB Locator Operations

Setting the LOB Column/Attribute to contain a locator

Before you can start writing data to an internal LOB, the LOB column/attribute must be made non-null, that is, it must contain a locator. Similarly, before you can start accessing the BFILE value, the BFILE column/attribute must be made non-null.

Invoking the EMPTY_BLOB() or EMPTY_CLOB() function in and of itself does not raise an exception. However, using a LOB locator that was set to empty to access or manipulate the LOB value in any PL/SQL DBMS_LOB or OCI routine will raise an exception. Valid places where empty LOB locators may be used include the VALUES clause of an INSERT statement and the SET clause of an UPDATE statement.

The following INSERT statement

Similarly, the LOB attributes for the Map_typ column in Multimedia_tab can be initialized to NULL or set to empty as shown below. Note that you cannot initialize a LOB object attribute with a literal.

INSERT INTO Multimedia_tab 
  VALUES (1, EMPTY_CLOB(), EMPTY_CLOB(), NULL, EMPTY_BLOB(), 
          EMPTY_BLOB(), NULL, NULL, NULL, 
          Map_typ('Moon Mountain', 23, 34, 45, 56, EMPTY_BLOB(), NULL);

Accessing a LOB through a locator

SELECTing a LOB

Performing a SELECT on a LOB returns the locator instead of the LOB value. In the following PL/SQL fragment you select the LOB locator for story and place it in the PL/SQL locator variable Image1 defined in the program block. When you use PL/SQL DBMS_LOB functions to manipulate the LOB value, you refer to the LOB using the locator.


DECLARE
    Image1       BLOB;
    ImageNum     INTEGER := 101;
BEGIN
    SELECT story INTO Image1 FROM Multimedia_tab
        WHERE clip_id = ImageNum;
    DBMS_OUTPUT.PUT_LINE('Size of the Image is: ' ||
        DBMS_LOB.GETLENGTH(Image1));
    /* more LOB routines */
END;

In the case of OCI, locators are mapped to locator pointers which are used to manipulate the LOB value. As mentioned before, the OCI LOB interface is described briefly in "Support Libraries" on page 1-309, and more extensively in the Oracle Call Interface Programmer's Guide.

LOB Locators and Transaction Boundaries

If you begin a transaction and then select a locator, the locator contains the transaction ID. Note that you can implicitly be in a transaction without explicitly beginning one. For example, SELECT ... FOR UPDATE implicitly begins a transaction. In such a case, the locator will contain a transaction ID. By contrast, if you select a locator outside of a transaction, the locator does not contain a transaction ID. Note that a transaction ID will not be assigned until the first DML statement executes. Therefore, locators that are selected out prior to such a DML statement will not contain a transaction ID.

You can always read the LOB data using the locator irrespective of whether the locator contains a transaction id. However, if the locator contains a transaction id, you cannot write to the LOB outside of that particular transaction. If the locator does not contain a transaction id, you can write to the LOB after beginning a transaction either explicitly or implicitly. We can show the relationship between transactions and locators by considering a few examples. However, if the locator contains a transaction id and the transaction is serializable, you cannot read or write outside of that particular transaction. If the transaction is non-serializable, you can read, but not write outside of that transaction. The following examples show the relationship between locators and non-serializable transactions

Select the Locator with No Current Transaction

Case 1:

    1. Select the locator with no current transaction.

      At this point, the locator does not contain a transaction id.

    2. Begin the transaction.

    3. Use the locator to read data from the LOB.

    4. Commit or rollback the transaction.

    5. Use the locator to read data from the LOB.

    6. Begin a transaction.

      The locator does not contain a transaction id.

    7. Use the locator to write data to the LOB.

      This operation is valid because the locator did not contain a transaction id prior to the write. After this call, the locator contains a transaction id.

Case 2:

    1. Select the locator with no current transaction.

      At this point, the locator does not contain a transaction id.

    2. Begin the transaction.

      The locator does not contain a transaction id.

    3. Use the locator to read data from the LOB.

      The locator does not contain a transaction id.

    4. Use the locator to write data to the LOB

      This operation is valid because the locator did not contain a transaction id prior to the write. After this call, the locator contains a transaction id. You can continue to read from and/or write to the LOB.

    5. Commit or rollback the transaction.

      The locator continues to contain the transaction id.

    6. Use the locator to read data from the LOB.

      This is a valid operation.

    7. Begin a transaction.

      The locator already contains the previous transaction's id.

    8. Use the locator to write data to the LOB.

      This write operation will fail because the locator does not contain the transaction id that matches the current transaction.

Select the Locator within a Transaction

Case 3:

    1. Select the locator within a transaction.

      At this point, the locator contains the transaction id.

    2. Begin the transaction.

      The locator contains the previous transaction's id.

    3. Use the locator to read data from the LOB.

      This operation is valid even though the transaction id in the locator does not match the current transaction.


      For more information on the LOB value that is Read see:

       

    4. Use the locator to write data to the LOB

      This operation fails because the transaction id in the locator does not match the current transaction.

Case 4:

    1. Begin a transaction.

    2. Select the locator.

      The locator contains the transaction id because it was selected within a transaction.

    3. Use the locator to read from and/or write to the LOB.

      These operations are valid.

    4. Commit or rollback the transaction.

      The locator continues to contain the transaction id.

    5. Use the locator to read data from the LOB.

      This operation is valid even though there's a transaction id in the locator and the transaction was previously committed or rolled back.


      For more information on the LOB value that is Read see:

       

    6. Use the locator to write data to the LOB

      This operation fails because the transaction id in the locator is for a transaction that was previously committed or rolled back.

Open, Close and IsOpen Interfaces for Internal LOBs

These interfaces let you open and close an internal LOB and test whether an internal LOB is already open.

It is not mandatory that you wrap all LOB operations inside the Open/Close APIs. The addition of this feature will not impact already-existing applications that write to LOBs without first opening them, since these calls did not exist in 8.0.

It is important to note that openness is associated with the LOB, not the locator. The locator does not save any information as to whether the LOB to which it refers is open.

Open and Close with Extensible Indexes

If you do not wrap LOB operations inside an Open/Close call, each modification to the LOB will implicitly open and close the LOB thereby firing any triggers on an extensible index. Note that in this case, any extensible indexes on the LOB will become updated as soon as LOB modifications are made. Therefore, extensible LOB indexes are always valid and may be used at any time. By contrast, if you wrap your LOB operations inside the Open/Close operations, triggers will not be fired for each LOB modification. Instead, the trigger on extensible indexes will be fired at the Close call. For example, you might design your application so that extensible indexes are not be updated until you call Close. However, this means that any extensible indexes on the LOB will not be valid in-between the Open/Close calls.

Note that the definition of a 'transaction' within which an open LOB value must be closed is one of the following:

A LOB opened when there is no transaction must be closed before the end of the session. If there are still open lobs at the end of the session, the openness will be discarded and no triggers on extensible indexes will be fired.

Errors

It is an error to commit the transaction before closing all opened LOBs that were opened by the transaction. When the error is returned, the openness of the open LOBs is discarded. At this point, the user must decide whether to close all the LOBs and reissue the call to commit, or rollback the transaction. Note that the changes to the LOB are not discarded if the COMMIT returns an error. At transaction rollback time, the openness of all open LOBs that are still open for that transaction will be discarded. Discarding the openness means that the LOBs won't be closed, thereby firing the triggers on extensible indexes.

It is also an error to open/close the same LOB twice either with different locators or with the same locator.

Example 1

DECLARE 
   Lob_loc1 CLOB; 
   Lob_loc2 CLOB;
   Buffer   VARCHAR2(32767); 
   Amount   BINARY_INTEGER := 32767; 
   Position INTEGER := 1; 
BEGIN 
   /* Select a LOB: */ 
   SELECT Story INTO Lob_loc1 FROM Multimedia_tab WHERE Clip_ID = 1; 

   /* The following statement opens the LOB outside of a transaction 
      so it must be closed before the session ends: */ 
   DBMS_LOB.OPEN(Lob_loc1, DBMS_LOB.LOB_READONLY); 
   /* The following statement begins a transaction. Note that Lob_loc1 and 
      Lob_loc2 point to the same LOB:  */ 
   SELECT Story INTO Lob_loc2 FROM Multimedia_tab WHERE Clip_ID = 1 for update;
   /* The following LOB open operation is allowed since this lob has  
      not been opened in this transaction:  */ 
   DBMS_LOB.OPEN(Lob_loc2, DBMS_LOB.LOB_READWRITE); 
   /* Fill the buffer with data to write to the LOB */
   buffer := 'A good story';
   Amount := 12;
   /* Write the buffer to the LOB: */ 
   DBMS_LOB.WRITE(Lob_loc2, Amount, Position, Buffer); 
   /* Closing the LOB is mandatory if you have opened it: */ 
   DBMS_LOB.CLOSE(Lob_loc2); 
   /* The COMMIT ends the transaction. It is allowed because all LOBs 
      opened in the transaction were closed. */ 
   COMMIT; 
   /* The the following statement closes the LOB that was opened  
       before the transaction started: */ 
   DBMS_LOB.CLOSE(Lob_loc1); 
END; 

Example 2:

DECLARE
   Lob_loc CLOB;
BEGIN
   /* Note that the FOR UPDATE clause starts a transaction: */
   SELECT Story INTO Lob_loc FROM Multimedia_tab WHERE Clip_ID = 1 for update;
   DBMS_LOB.OPEN(Lob_loc, DBMS_LOB.LOB_READONLY);
   /* COMMIT returns an error because there is still an open LOB associated
   with this transaction: */
   COMMIT;
END;

Indexing a LOB Column

You cannot build B-tree or bitmap indexes on a LOB column. However, depending on your application and its usage of the LOB column, you might be able to improve the performance of queries by building indexes specifically attuned to your domain. Oracle's extensibility interfaces allow for Extensible Indexing, a framework for implementing such domain specific indexes.


For more information regarding building domain specific indexes, see:

Oracle8i Data Cartridge Developer's Guide.  


Depending on the nature of the contents of the LOB column, one of the Oracle intermedia options could also be used for building indexes. For example, if a text document is stored in a CLOB column, you can build a text index (provided by Oracle) to speed up the performance of text-based queries over the CLOB column.


For more information regarding Oracle's intermedia options, see:

Oracle8i interMedia Audio, Image, and Video User's Guide and Reference and Oracle8i Context Cartridge Reference.  





Prev

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index