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.
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.
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.
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.
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. |
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.
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.
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.
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:
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.
A smart large object is not deleted until both of the following conditions are met:
To modify the data of a smart large object, perform the following steps:
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.
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 ]