Home | Previous Page | Next Page   Working with Smart Large Objects > Accessing a Smart Large Object >

Using ifx_lo Functions

This section describes how to select, open, delete, modify, and close a smart large object using ifx_lo functions. The section includes a code example at the end.

Selecting a Smart Large Object Using ifx_lo functions

A SELECT statement does not perform the actual output for the smart-large-object data. It does, however, establish a means for the application to identify a smart large object so that the application can then perform operations on the smart large object. Figure 8 shows how the database server transfers the data of a smart large object to the application.

Figure 8. Transferring Smart-Large-Object Data from Database Server to Client Application
This graphic illustrates the steps necessary to transfer smart-large-object data from a database server to a client application. This graphic is composed of two boxes in a vertical line and connected by a down facing arrow. The first box contains these two steps:  1. Execute SELECT statement. 2. Obtain smart-large-object pointer structure. The second box contains this step: 3. Use client functions to access data through the smart-large-object pointer structure.

Opening a Smart Large Object Using ifx_lo functions

When you open a smart large object, you obtain a smart-large-object file descriptor for the smart large object. Through the smart-large-object file descriptor you can access the data of a smart large object as if it were in an operating-system file.

Access Modes

When you open a smart large object, you specify the access mode for the data. The access mode determines which read and write operations are valid on the open smart large object. The following table describes the access modes that ifx_lo_open() and ifx_lo_create() support.

Access Mode Purpose Constant
Read only Only read operations are valid on the data. LO_RDONLY
Dirty read Lets you read uncommitted data pages for the smart large object. You cannot write to a smart large object after you set the mode to LO_DIRTY_READ. When you set this flag, you reset the current transaction isolation mode to dirty read for this smart large object.

Do not base updates on data that you obtain from a smart large object in dirty-read mode.

LO_DIRTY_READ
Write only Only write operations are valid on the data. LO_WRONLY
Append Intended for use in conjunction with LO_WRONLY or LO_RDWR. Sets the location pointer to the end of the object immediately prior to each write. Appends any data you write to the end of the smart large object. If LO_APPEND is used alone, the object is opened for reading only. LO_APPEND
Read/write Both read and write operations are valid on the data. LO_RDWR
Buffered access Uses standard database server buffer pool. LO_BUFFER
Lightweight I/O Uses private buffers from the session pool of the database server. LO_NOBUFFER

When you open a smart large object with LO_APPEND only, the database server opens the smart large object as read-only. Seek operations and read operations move the file pointer. Write operations fail and do not move the file pointer.

You can mask the LO_APPEND flag with another access mode. In any of these OR combinations, the seek operation remains unaffected. The following table shows the effect on the read and write operations that each of the OR combinations has.

OR Operation Read Operations Write Operations
LO_RDONLY | LO_APPEND Occur at the file position and then move the file position to the end of the data that has been read. Fail and do not move the file position.
LO_WRONLY | LO_APPEND Fail and do not move the file position. Move the file position to the end of the smart large object and then write the data; file position is at the end of the data after the write.
LO_RDWR | LO_APPEND Occur at the file position and then move the file position to the end of the data that has been read. Move the file position to the end of the smart large object and then write the data; file position is at the end of the data after the write.

Lightweight I/O

When the database server accesses smart large objects, it uses buffers from the buffer pool for buffered access. Unbuffered access is called lightweight I/O. Lightweight I/O uses private buffers instead of the buffer pool to hold smart large objects. These private buffers are allocated out of the database server session pool.

Lightweight I/O allows you to bypass the overhead of the least-recently-used (LRU) queues that the database server uses to manage the buffer pool. For more information about LRU queues, see your IBM Informix: Performance Guide.

You can specify lightweight I/O by setting the flags parameter to LO_NOBUFFER when you create or open a smart large object. To specify buffered access, which is the default, use the LO_BUFFER flag.

Important:
Keep the following issues in mind when you use lightweight I/O:

The database server imposes the following restrictions on switching from lightweight I/O to buffered I/O:

You can use the database server utility onspaces to specify lightweight I/O for all smart large objects in an sbspace. For more information on the onspaces utility, see your IBM Informix: Administrator's Guide.

Smart-Large-Object Locks

To prevent simultaneous access to smart-large-object data, the database server locks a smart large object when you open it. Locks on smart large objects are different than row locks. If you retrieve a smart large object from a row, the database server might hold a row lock as well as a smart-large-object lock. The database server locks smart large objects because many columns can contain the same smart-large-object data.

To specify the lock mode of a smart large object, pass the access-mode flags, LO_RDONLY, LO_DIRTY_READ, LO_APPEND, LO_WRONLY, LO_RDWR, and LO_TRUNC, to the ifx_lo_open() and ifx_lo_create() functions. When you specify LO_RDONLY, the database server places a lock on the smart-large-object data. When you specify LO_DIRTY_READ, the database server does not place a lock on the smart-large-object data. If you specify any other access-mode flag, the database server obtains an update lock, which it promotes to an exclusive lock on first write or other update operation.

Share and update locks (read-only mode or write mode before an update operation occurs) are held until your application takes one of the following actions:

Exclusive locks are held until the end of a transaction even if you close the smart large object.

Important:
You lose the lock at the end of a transaction even if the smart large object remains open. When the database server detects that a smart large object does not have an active lock, it places a new lock the next time that you access the smart large object. The lock that it places is based on the original open mode of the smart large object.

Duration of an Open Operation on a Smart Large Object

After you open a smart large object with the ifx_lo_create() function or the ifx_lo_open() function, it remains open until one of the following events occurs:

Warning:
The end of the current transaction does not close a smart large object. It does, however, release any lock on a smart large object.

Close smart large objects as soon as you finish using them. Leaving smart large objects open unnecessarily consumes system memory. Leaving many smart large objects open can eventually produce an out-of-memory condition.

Deleting a Smart Large Object

A smart large object is not deleted until both of the following conditions are met:

Modifying a Smart Large Object

To modify the data of a smart large object, perform the following steps:

  1. Read and write the data in the open smart large object.
  2. Use an UPDATE or INSERT statement to store the smart-large-object pointer in the database.

Closing a Smart Large Object

After you finish modifying a smart large object, call ifx_lo_close() to deallocate the resources that are assigned to it. When the resources are freed, you can reallocate them to other structures that your application needs. You can also reallocate the smart-large-object file descriptor to other smart large objects.

Example of Retrieving a Smart Large Object from the Database Using ifx_lo Functions

The following code example, loselect.c, shows how to retrieve a smart large object from the database. You can find the loselect.c file in the %INFORMIXDIR%/demo/clidemo directory on UNIX platforms and in the %INFORMIXDIR%\demo\odbcdemo directory on Windows platforms. You can also find instructions on how to build the odbc_demo database in the same location.

/*
**    loselect.c
**
** To access a smart large object
**    SQLBindCol
**    SQLBindParameter
**    SQLConnect
**    SQLFetch
**    SQLFreeStmt
**    SQLGetInfo
**    SQLDisconnect
**    SQLExecDirect
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef NO_WIN32
#include <io.h>
#include <windows.h>
#include <conio.h>
#endif /*NO_WIN32*/

#include "infxcli.h"

#define ERRMSG_LEN  200

UCHAR   defDsn[] = "odbc_demo";

int checkError (SQLRETURN     rc,
               SQLSMALLINT    handleType,
               SQLHANDLE      handle,
               char           *errmsg)
{
   SQLRETURN   retcode = SQL_SUCCESS;

   SQLSMALLINT errNum = 1;
   SQLCHAR     sqlState[6];
   SQLINTEGER  nativeError;
   SQLCHAR     errMsg[ERRMSG_LEN];
   SQLSMALLINT textLengthPtr;


   if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
   {
      while (retcode != SQL_NO_DATA)
      {
         retcode = SQLGetDiagRec (handleType, handle, errNum, sqlState,
               &nativeError, errMsg, ERRMSG_LEN, &textLengthPtr);

         if (retcode == SQL_INVALID_HANDLE)
         {
            fprintf (stderr, "checkError function was called with an
               invalid handle!!\n");
            return 1;
         }

         if ((retcode == SQL_SUCCESS) || (retcode ==
               SQL_SUCCESS_WITH_INFO))
            fprintf (stderr, "ERROR: %d:  %s : %s \n", nativeError,
                  sqlState, errMsg);

         errNum++;
      }

      fprintf (stderr, "%s\n", errmsg);
      return 1;   /* all errors on this handle have been reported */
   }
   else
      return 0;   /* no errors to report */
}

int main (long    argc,
         char     *argv[])
{
   /* Declare variables
   */

   /* Handles */
   SQLHDBC     hdbc;
   SQLHENV     henv;
   SQLHSTMT    hstmt;

   /* Smart large object file descriptor */
   long        lofd;
   long           lofd_valsize = 0;

   /* Smart large object pointer structure */
   char*       loptr_buffer;
   short       loptr_size;
   long        loptr_valsize = 0;

   /* Smart large object status structure */
   char*       lostat_buffer;
   short       lostat_size;
   long        lostat_valsize = 0;

   /* Smart large object data */
   char*       lo_data;
   long        lo_data_valsize = 0;

   /* Miscellaneous variables */
   UCHAR       dsn[20]; /*name of the DSN used for connecting to the
                  database*/
   SQLRETURN   rc = 0;
   int         in;

   char*       selectStmt = "SELECT advert FROM item WHERE item_num =
                  1004";
   long        mode = LO_RDONLY;
   long        lo_size;
   long        cbMode = 0, cbLoSize = 0;


/* STEP 1.  Get data source name from command line (or use default)
   **       Allocate the environment handle and set ODBC version
   **       Allocate the connection handle
   **       Establish the database connection
   **       Allocate the statement handle
   */

   /* If(dsn is not explicitly passed in as arg) */
   if (argc != 2)
   {
      /* Use default dsn - odbc_demo */
      fprintf (stdout, "\nUsing default DSN : %s\n", defDsn);
      strcpy ((char *)dsn, (char *)defDsn);
   }
   else 
   {
      /* Use specified dsn */
      strcpy ((char *)dsn, (char *)argv[1]);
      fprintf (stdout, "\nUsing specified DSN : %s\n", dsn);
   }

   /* Allocate the Environment handle */
   rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
   if (rc != SQL_SUCCESS)
   {
      fprintf (stdout, "Environment Handle Allocation
            failed\nExiting!!\n");
      return (1);
   }

   /* Set the ODBC version to 3.5 */
   rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION,
         (SQLPOINTER)SQL_OV_ODBC3, 0);
   if (checkError (rc, SQL_HANDLE_ENV, henv, "Error in Step 1 --
         SQLSetEnvAttr failed\nExiting!!\n"))
      return (1);

   /* Allocate the connection handle */
   rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);
   if (checkError (rc, SQL_HANDLE_ENV, henv, "Error in Step 1 -- Connection
         Handle Allocation failed\nExiting!!\n"))
      return (1);

   /* Establish the database connection */
   rc = SQLConnect (hdbc, dsn, SQL_NTS, "", SQL_NTS, "", SQL_NTS);
   if (checkError (rc, SQL_HANDLE_DBC, hdbc, "Error in Step 1 -- SQLConnect
         failed\nExiting!!"))
      return (1);
   /* Allocate the statement handle */
   rc = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt);
   if (checkError (rc, SQL_HANDLE_DBC, hdbc, "Error in Step 1 -- Statement
         Handle Allocation failed\nExiting!!"))
      return (1);

   fprintf (stdout, "STEP 1 done...connected to database\n");


/* STEP 2.  Select a smart-large object from the database
   **       -- the select statement executed is -
   **       "SELECT advert FROM item WHERE item_num = 1004"
   */

   /* Execute the select statement */
   rc = SQLExecDirect (hstmt, selectStmt, SQL_NTS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 2 --
         SQLExecDirect failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 2 done...select statement executed...smart large
         object retrieved from the databse\n");


/* STEP 3.  Get the size of the smart large object pointer structure.
   **       Allocate a buffer to hold the structure.
   **       Get the smart large object pointer structure from the
   **       database.
   **       Close the result set cursor.
   */

   /* Get the size of the smart large object pointer structure */
   rc = SQLGetInfo (hdbc, SQL_INFX_LO_PTR_LENGTH, &loptr_size,
         sizeof(loptr_size),
         NULL);
   if (checkError (rc, SQL_HANDLE_DBC, hdbc, "Error in Step 3 -- SQLGetInfo
         failed\n"))
      goto Exit;

   /* Allocate a buffer to hold the smart large object pointer structure */
   loptr_buffer = malloc (loptr_size);

   /* Bind the smart large object pointer structure buffer allocated to the
         column in the result set & fetch it from the database */
   rc = SQLBindCol (hstmt, 1, SQL_C_BINARY, loptr_buffer, loptr_size,
         &loptr_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 3 --
         SQLBindCol failed\n"))
      goto Exit;

   rc = SQLFetch (hstmt);
   if (rc == SQL_NO_DATA_FOUND)
   {
      fprintf (stdout, "No Data Found\nExiting!!\n");
      goto Exit;
   }
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 3 -- SQLFetch
         failed\n"))
      goto Exit;

   /* Close the result set cursor */
   rc = SQLCloseCursor (hstmt);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 3 --
         SQLCloseCursor failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 3 done...smart large object pointer structure
      fetched from the database\n");


/* STEP 4.  Use the smart large object's pointer structure to open it
   **       and obtain the smart large object file descriptor.
   **       Reset the statement parameters.
   */

   rc = SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_LONG,
         SQL_INTEGER, (UDWORD)0, 0, &lofd, sizeof(lofd), &lofd_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 4 --
         SQLBindParameter failed (param 1)\n"))
      goto Exit;

   rc = SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY,
         SQL_INFX_UDT_FIXED, (UDWORD)loptr_size, 0, loptr_buffer,
         loptr_size, &loptr_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 4 --
         SQLBindParameter failed (param 2)\n"))
      goto Exit;

   rc = SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT, SQL_C_LONG,
         SQL_INTEGER, (UDWORD)0, 0, &mode, sizeof(mode), &cbMode);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 4 --
         SQLBindParameter failed (param 3)\n"))
      goto Exit;

   rc = SQLExecDirect (hstmt, "{? = call ifx_lo_open(?, ?)}", SQL_NTS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 4 --
         SQLExecDirect failed\n"))
      goto Exit;

   /* Reset the statement parameters */
   rc = SQLFreeStmt (hstmt, SQL_RESET_PARAMS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 4 --
         SQLFreeStmt failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 4 done...smart large object opened... file
         descriptor obtained\n");


/* STEP 5.  Get the size of the smart large object status structure.
   **       Allocate a buffer to hold the structure.
   **       Get the smart large object status structure from the
   **       database.
   **       Reset the statement parameters.
   */

   /* Get the size of the smart large object status structure */
   rc = SQLGetInfo (hdbc, SQL_INFX_LO_STAT_LENGTH, &lostat_size,
         sizeof(lostat_size), NULL);
   if (checkError (rc, SQL_HANDLE_DBC, hdbc, "Error in Step 5 -- SQLGetInfo
         failed\n"))
      goto Exit;

   /* Allocate a buffer to hold the smart large object status structure. */
   lostat_buffer = malloc(lostat_size);

   /* Get the smart large object status structure from the database. */
   rc = SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG,
         SQL_INTEGER, (UDWORD)0, 0, &lofd, sizeof(lofd), &lofd_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 5 --
         SQLBindParameter failed (param 1)\n"))
      goto Exit;

   rc = SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,
         SQL_INFX_UDT_FIXED, (UDWORD)lostat_size, 0, lostat_buffer,
         lostat_size, &lostat_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 5 --
         SQLBindParameter failed (param 2)\n"))
      goto Exit;

   rc = SQLExecDirect (hstmt, "{call ifx_lo_stat(?, ?)}", SQL_NTS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 5 --
         SQLExecDiret failed\n"))
      goto Exit;

   /* Reset the statement parameters */
   rc = SQLFreeStmt (hstmt, SQL_RESET_PARAMS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 5 --
         SQLFreeStmt failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 5 done...smart large object status structure
         fetched from the database\n");


/* STEP 6.  Use the smart large object's status structure to get the
   **       size of the smart large object.
   **       Reset the statement parameters.
   */

   /* Use the smart large object status structure to get the size of the
         smart large object */
   rc = SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY,
         SQL_INFX_UDT_FIXED, (UDWORD)lostat_size, 0, lostat_buffer,
         lostat_size, &lostat_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 6 --
         SQLBindParameter failed (param 1)\n"))
      goto Exit;

   rc = SQLBindParameter (hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG,
         SQL_BIGINT, (UDWORD)0, 0, &lo_size, sizeof(lo_size), &cbLoSize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 6 --
         SQLBindParameter failed (param 1)\n"))
      goto Exit;

   rc = SQLExecDirect (hstmt, "{call ifx_lo_stat_size(?, ?)}", SQL_NTS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 6 --
         SQLExecDirect failed\n"))
      goto Exit;

   /* Reset the statement parameters */
   rc = SQLFreeStmt (hstmt, SQL_RESET_PARAMS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 6 --
         SQLFreeStmt failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 6 done...smart large object size = %ld bytes\n",
         lo_size);


/* STEP 7.  Allocate a buffer to hold the smart large object's data.
   **       Read the smart large object's data using its file descriptor.
   **       Null-terminate the last byte of the smart large-object's data.
   **       Print out the contents of the smart large object.
   **       Reset the statement parameters.
   */

   /* Allocate a buffer to hold the smart large object's data chunks */
   lo_data = malloc (lo_size + 1);

   /* Read the smart large object's data */
   rc = SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG,
         SQL_INTEGER, (UDWORD)0, 0, &lofd, sizeof(lofd), &lofd_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 7 --
         SQLBindParameter failed (param 1)\n"))
      goto Exit;

   rc = SQLBindParameter (hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR,
         lo_size, 0, lo_data, lo_size, &lo_data_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 7 --
         SQLBindParameter failed (param 2)\n"))
      goto Exit;

   rc = SQLExecDirect (hstmt, "{call ifx_lo_read(?, ?)}", SQL_NTS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 7 --
         SQLExecDirect failed\n"))
      goto Exit;

   /* Null-terminate the last byte of the smart large objects data */
   lo_data[lo_size] = '\0';

   /* Print the contents of the smart large object */
   fprintf (stdout, "Smart large object contents are.....\n\n\n%s\n\n\n",
         lo_data);

   /* Reset the statement parameters */
   rc = SQLFreeStmt (hstmt, SQL_RESET_PARAMS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 7 --
         SQLFreeStmt failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 7 done...smart large object read completely\n");



/* STEP 8.  Close the smart large object.
   */

   rc = SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG,
         SQL_INTEGER, (UDWORD)0, 0, &lofd, sizeof(lofd), &lofd_valsize);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 8 --
         SQLBindParameter failed\n"))
      goto Exit;

   rc = SQLExecDirect (hstmt, "{call ifx_lo_close(?)}", SQL_NTS);
   if (checkError (rc, SQL_HANDLE_STMT, hstmt, "Error in Step 8 --
         SQLExecDirect failed\n"))
      goto Exit;

   fprintf (stdout, "STEP 8 done...smart large object closed\n");


/* STEP 9.  Free the allocated buffers.
   */

   free (loptr_buffer);
   free (lostat_buffer);
   free (lo_data);

   fprintf (stdout, "STEP 9 done...smart large object buffers freed\n");

   Exit:

   /* CLEANUP: Close the statement handle
   **          Free the statement handle
   **          Disconnect from the datasource
   **          Free the connection and environment handles
   **          Exit
   */

   /* Close the statement handle */
   SQLFreeStmt (hstmt, SQL_CLOSE);

   /* Free the statement handle */
   SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

   /* Disconnect from the data source */
   SQLDisconnect (hdbc);

   /* Free the environment handle and the database connection handle */
   SQLFreeHandle (SQL_HANDLE_DBC, hdbc);
   SQLFreeHandle (SQL_HANDLE_ENV, henv);

   fprintf (stdout,"\n\nHit <Enter> to terminate the program...\n\n");
   in = getchar ();
   return (rc);
}
Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]