/****************************************************************************
** (c) Copyright IBM Corp. 2007 All rights reserved.
** 
** The following sample of source code ("Sample") is owned by International 
** Business Machines Corporation or one of its subsidiaries ("IBM") and is 
** copyrighted and licensed, not sold. You may use, copy, modify, and 
** distribute the Sample in any form without payment to IBM, for the purpose of 
** assisting you in the development of your applications.
** 
** The Sample code is provided to you on an "AS IS" basis, without warranty of 
** any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR 
** IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do 
** not allow for the exclusion or limitation of implied warranties, so the above 
** limitations or exclusions may not apply to you. IBM shall not be liable for 
** any damages you suffer as a result of using, copying, modifying or 
** distributing the Sample, even if IBM has been advised of the possibility of 
** such damages.
*****************************************************************************
**
** SOURCE FILE NAME: dtlob.c
**                                                                        
** SAMPLE: How to read and write LOB data
**
** CLI FUNCTIONS USED:
**         SQLAllocHandle -- Allocate Handle
**         SQLBindCol -- Bind a Column to an Application Variable or
**                       LOB locator
**         SQLBindFileToCol -- Bind LOB File Reference to LOB Column
**         SQLBindFileToParam -- Bind LOB File Reference to LOB Parameter
**         SQLBindParameter -- Bind a Parameter Marker to a Buffer or
**                             LOB locator
**         SQLCloseCursor -- Close Cursor and Discard Pending Results
**         SQLEndTran -- End Transactions of a Connection
**         SQLExecDirect -- Execute a Statement Directly
**         SQLExecute -- Execute a Statement
**         SQLFetch -- Fetch Next Row
**         SQLFreeHandle -- Free Handle Resources
**         SQLGetData -- Get Data From a Column
**         SQLGetLength -- Retrieve Length of a String Value
**         SQLGetPosition -- Return Starting Position of String
**         SQLGetSubString -- Retrieve Portion of a String Value
**         SQLParamData -- Get Next Parameter for which a Data Value
**                         is Needed
**         SQLPrepare -- Prepare a Statement
**         SQLPutData -- Passing Data Value for a Parameter
**         SQLSetConnectAttr -- Set Connection Attributes
**         SQLSetParam -- Bind a Parameter Marker to a Buffer or LOB locator
**
**                           
*****************************************************************************
**
** For more information on the sample programs, see the README file.
**
** For information on developing CLI applications, see the CLI Guide
** and Reference.
**
** For information on using SQL statements, see the SQL Reference.
**
** For the latest information on programming, building, and running DB2 
** applications, visit the DB2 application development website: 
**     http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp
****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlcli1.h>
#include "utilcli.h" /* header file for CLI sample code */

int BlobReadAsAWhole(SQLHANDLE);
int BlobReadInPieces(SQLHANDLE);
int BlobWriteAsAWhole(SQLHANDLE);
int BlobWriteInPieces(SQLHANDLE);
int ClobReadASelectedPiece(SQLHANDLE);

int main(int argc, char *argv[])
{
  SQLRETURN cliRC = SQL_SUCCESS;
  int rc = 0;
  SQLHANDLE henv; /* environment handle */
  SQLHANDLE hdbc; /* connection handle */

  char dbAlias[SQL_MAX_DSN_LENGTH + 1];
  char user[MAX_UID_LENGTH + 1];
  char pswd[MAX_PWD_LENGTH + 1];

  /* check the command line arguments */
  rc = CmdLineArgsCheck1(argc, argv, dbAlias, user, pswd);
  if (rc != 0)
  {
    return rc;
  }

  printf("\nTHIS SAMPLE SHOWS HOW TO READ AND WRITE LOBs.\n");

  /* initialize the CLI application by calling a helper
     utility function defined in utilcli.c */
  rc = CLIAppInit(dbAlias,
                  user,
                  pswd,
                  &henv,
                  &hdbc,
                  (SQLPOINTER)SQL_AUTOCOMMIT_ON);
  if (rc != 0)
  {
    return rc;
  }

  /* read all of the BLOB data at once */
  rc = BlobReadAsAWhole(hdbc);
  /* read the BLOB data piece by piece */
  rc = BlobReadInPieces(hdbc);
  /* write all of the BLOB data at once */
  rc = BlobWriteAsAWhole(hdbc);
  /* write the BLOB data piece by piece */
  rc = BlobWriteInPieces(hdbc);
  /* read a specific part of CLOB data */
  rc = ClobReadASelectedPiece(hdbc);

  /* terminate the CLI application by calling a helper
     utility function defined in utilcli.c */
  rc = CLIAppTerm(&henv, &hdbc, dbAlias);

  return rc;
} /* main */

/* read all of the BLOB data at once */
int BlobReadAsAWhole(SQLHANDLE hdbc)
{
  SQLRETURN cliRC = SQL_SUCCESS;
  int rc = 0;
  SQLHANDLE hstmt; /* statement handle */
  SQLCHAR *stmt = (SQLCHAR *)"SELECT picture "
                             "  FROM emp_photo "
                             "  WHERE empno  = ? AND photo_format = ?";
  char empno[10], photo_format[10];
  SQLUINTEGER fileOption = SQL_FILE_OVERWRITE;
  SQLINTEGER fileInd = 0;
  SQLSMALLINT fileNameLength = 14;
  SQLCHAR fileNameBase[] = "photo1";
  SQLCHAR fileName[14] = "";

  printf("\n-----------------------------------------------------------");
  printf("\nUSE THE CLI FUNCTIONS\n");
  printf("  SQLSetConnectAttr\n");
  printf("  SQLAllocHandle\n");
  printf("  SQLPrepare\n");
  printf("  SQLBindParameter\n");
  printf("  SQLBindFileToCol\n");
  printf("  SQLExecute\n");
  printf("  SQLFetch\n");
  printf("  SQLCloseCursor\n");
  printf("  SQLFreeHandle\n");
  printf("TO READ ALL OF THE BLOB DATA AT ONCE:\n");

  /* set AUTOCOMMIT on */
  cliRC = SQLSetConnectAttr(hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            (SQLPOINTER)SQL_AUTOCOMMIT_ON,
                            SQL_NTS);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Prepare the statement\n");
  printf("    SELECT picture\n");
  printf("      FROM emp_photo\n");
  printf("      WHERE empno  = ? AND photo_format = ?\n");

  /* prepare the statement */
  cliRC = SQLPrepare(hstmt, stmt, SQL_NTS);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  printf("\n  Bind parameters to the statement\n");

  /* bind the first parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           1,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           empno,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* bind the second parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           2,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           photo_format,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* bind a file to the BLOB column */
  rc = SQLBindFileToCol(hstmt,
                        1,
                        fileName,
                        &fileNameLength,
                        &fileOption,
                        14,
                        NULL,
                        &fileInd);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* ----------------read data in a *.bmp file ------------------------*/

  printf("\n  Execute the prepared statement for\n");
  printf("    empno = '000140'\n");
  printf("    photo_format = 'bitmap'\n");
  strcpy(empno, "000140");
  strcpy(photo_format, "bitmap");

  /* execute the statement */
  cliRC = SQLExecute(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* set the value for the fileName */
  sprintf((char *)fileName, "%s.bmp", fileNameBase);

  printf("\n  Fetch BLOB data in the file '%s'.\n", fileName);

  /* fetch the result */
  cliRC = SQLFetch(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }

  /* close the cursor */
  cliRC = SQLCloseCursor(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* ----------------read data in a *.gif file ------------------------*/

  printf("\n  Execute the prepared statement for\n");
  printf("    empno = '000140'\n");
  printf("    photo_format = 'gif'\n");
  strcpy(empno, "000140");
  strcpy(photo_format, "gif");

  /* execute the statement */
  cliRC = SQLExecute(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* set the value for the fileName */
  sprintf((char *)fileName, "%s.gif", fileNameBase);

  printf("\n  Fetch BLOB data in the file '%s'.\n", fileName);

  /* fetch the result */
  cliRC = SQLFetch(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }

  /* close the cursor */
  cliRC = SQLCloseCursor(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* free the statement handle */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  return rc;
} /* BlobReadAsAWhole */

/* read the BLOB data piece by piece */
int BlobReadInPieces(SQLHANDLE hdbc)
{
  SQLRETURN cliRC = SQL_SUCCESS;
  int rc = 0;
  SQLHANDLE hstmt; /* statement handle */
  SQLCHAR *stmt = (SQLCHAR *)"SELECT picture "
                             "  FROM emp_photo "
                             "  WHERE empno  = ? AND photo_format = ?";
  char empno[10], photo_format[10];
  SQLCHAR fileNameBase[] = "photo2";
  char fileName[14] = "";
  FILE *pFile;
  SQLCHAR buffer[BUFSIZ];
  SQLINTEGER bufInd;

  printf("\n-----------------------------------------------------------");
  printf("\nUSE THE CLI FUNCTIONS\n");
  printf("  SQLSetConnectAttr\n");
  printf("  SQLAllocHandle\n");
  printf("  SQLPrepare\n");
  printf("  SQLBindParameter\n");
  printf("  SQLExecute\n");
  printf("  SQLFetch\n");
  printf("  SQLGetData\n");
  printf("  SQLFreeHandle\n");
  printf("TO READ BLOB DATA IN PIECES:\n");

  /* set AUTOCOMMIT on */
  cliRC = SQLSetConnectAttr(hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            (SQLPOINTER)SQL_AUTOCOMMIT_ON,
                            SQL_NTS);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Prepare the statement\n");
  printf("    SELECT picture\n");
  printf("      FROM emp_photo\n");
  printf("      WHERE empno  = ? AND photo_format = ?\n");

  /* prepare the statement */
  cliRC = SQLPrepare(hstmt, stmt, SQL_NTS);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  printf("\n  Bind parameters to the statement\n");

  /* bind the first parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           1,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           empno,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* bind the second parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           2,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           photo_format,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* ----------------read data in a *.bmp file ------------------------*/

  printf("\n  Execute the prepared statement for\n");
  printf("    empno = '000140'\n");
  printf("    photo_format = 'bitmap'\n");
  strcpy(empno, "000140");
  strcpy(photo_format, "bitmap");

  /* execute the statement */
  cliRC = SQLExecute(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  sprintf(fileName, "%s.bmp", fileNameBase);
  printf("\n  Fetch BLOB data in the file %s.\n", fileName);

  /* fetch the result */
  cliRC = SQLFetch(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }

  /* open the file */
  pFile = fopen(fileName, "w+b");
  if (pFile == NULL)
  {
    printf(">---- ERROR Opening File -------");

    /* free the statement handle */
    cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

    return 1;
  }

  /* get BUFSIZ bytes at a time */
  /* bufInd indicates number of bytes remaining */
  cliRC = SQLGetData(hstmt,
                     1,
                     SQL_C_BINARY,
                     (SQLPOINTER)buffer,
                     BUFSIZ,
                     &bufInd);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }

  while (cliRC == SQL_SUCCESS_WITH_INFO || cliRC == SQL_SUCCESS)
  {
    if (bufInd > BUFSIZ) /* full buffer */
    {
      fwrite(buffer, sizeof(char), BUFSIZ, pFile);
    }
    else /* partial buffer on last SQLGetData */
    {
      fwrite(buffer, sizeof(char), bufInd, pFile);
    }

    /* get data from a column */
    cliRC = SQLGetData(hstmt,
                       1,
                       SQL_C_BINARY,
                       (SQLPOINTER)buffer,
                       BUFSIZ,
                       &bufInd);
    STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);
  }

  /* close the file */
  fflush(pFile);
  fclose(pFile);

  /* close the cursor */
  cliRC = SQLCloseCursor(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* ----------------read data in a *.gif file ------------------------*/

  printf("\n  Execute the prepared statement for\n");
  printf("    empno = '000140'\n");
  printf("    photo_format = 'gif'\n");
  strcpy(empno, "000140");
  strcpy(photo_format, "gif");

  /* execute the statement */
  cliRC = SQLExecute(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  sprintf(fileName, "%s.gif", fileNameBase);
  printf("\n  Fetch BLOB data in the file %s.\n", fileName);

  /* fetch the result */
  cliRC = SQLFetch(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }

  /* open the file */
  pFile = fopen(fileName, "w+b");
  if (pFile == NULL)
  {
    printf(">---- ERROR Opening File -------");

    /* free the statement handle */
    cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

    return 1;
  }

  /* get BUFSIZ bytes at a time */
  /* bufInd indicates number of bytes remaining */
  cliRC = SQLGetData(hstmt,
                     1,
                     SQL_C_BINARY,
                     (SQLPOINTER)buffer,
                     BUFSIZ,
                     &bufInd);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }
  while (cliRC == SQL_SUCCESS_WITH_INFO || cliRC == SQL_SUCCESS)
  {
    if (bufInd > BUFSIZ) /* full buffer */
    {
      fwrite(buffer, sizeof(char), BUFSIZ, pFile);
    }
    else /* partial buffer on last SQLGetData */
    {
      fwrite(buffer, sizeof(char), bufInd, pFile);
    }

    /* get data from a column */
    cliRC = SQLGetData(hstmt,
                       1,
                       SQL_C_BINARY,
                       (SQLPOINTER)buffer,
                       BUFSIZ,
                       &bufInd);
    STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);
  }

  /* close the file */
  fflush(pFile);
  fclose(pFile);

  /* close the cursor */
  cliRC = SQLCloseCursor(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* free the statement handle */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  return rc;
} /* BlobReadInPieces */

/* write all of the BLOB data at once */
int BlobWriteAsAWhole(SQLHANDLE hdbc)
{
  SQLRETURN cliRC = SQL_SUCCESS;
  int rc = 0;
  SQLHANDLE hstmt; /* statement handle */
  SQLCHAR *stmt = (SQLCHAR *)
    "INSERT INTO emp_photo(empno, photo_format, picture) VALUES(?, ?, ?)";
  SQLCHAR empno[10], photo_format[10];
  SQLUINTEGER fileOption = SQL_FILE_READ;
  SQLINTEGER fileInd = 0;
  SQLSMALLINT fileNameLength = 14;
  SQLCHAR fileNameBase[] = "photo1";
  SQLCHAR fileName[14] = "";

  printf("\n-----------------------------------------------------------");
  printf("\nUSE THE CLI FUNCTIONS\n");
  printf("  SQLSetConnectAttr\n");
  printf("  SQLAllocHandle\n");
  printf("  SQLPrepare\n");
  printf("  SQLBindParameter\n");
  printf("  SQLBindFileToParam\n");
  printf("  SQLExecute\n");
  printf("  SQLEndTran\n");
  printf("  SQLFreeHandle\n");
  printf("TO WRITE ALL OF THE BLOB DATA AT ONCE:\n");

  /* set AUTOCOMMIT OFF */
  cliRC = SQLSetConnectAttr(hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            (SQLPOINTER)SQL_AUTOCOMMIT_OFF,
                            SQL_NTS);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Transactions enabled.\n");

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Prepare the statement\n");
  printf("    INSERT INTO emp_photo(empno, photo_format, picture) ");
  printf("VALUES(?, ?, ?)\n");

  /* prepare the statement */
  cliRC = SQLPrepare(hstmt, stmt, SQL_NTS);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  printf("\n  Bind parameters to the statement\n");

  /* bind the first parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           1,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           empno,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* bind the second parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           2,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           photo_format,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* bind the file parameter */
  rc = SQLBindFileToParam(hstmt,
                          3,
                          SQL_BLOB,
                          fileName,
                          &fileNameLength,
                          &fileOption,
                          14,
                          &fileInd);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* ----------------write data from a *.bmp file ------------------------*/

  strcpy((char *)empno, "000240");
  strcpy((char *)photo_format, "bitmap");
  sprintf((char *)fileName, "%s.bmp", fileNameBase);
  printf("\n  Execute the prepared statement for\n");
  printf("    empno = '000240'\n");
  printf("    photo_format = 'bitmap'\n");
  printf("    fileName = %s\n", fileName);

  /* execute the statement */
  cliRC = SQLExecute(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  printf("\n  Rolling back the transaction...\n");

  /* end transactions on a connection */
  cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("  Transaction rolled back.\n");

  /* free the statement handle */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  return rc;
} /* BlobWriteAsAWhole */

/* write the BLOB data piece by piece */
int BlobWriteInPieces(SQLHANDLE hdbc)
{
  SQLRETURN cliRC = SQL_SUCCESS;
  int rc = 0;
  SQLHANDLE hstmt; /* statement handle */
  SQLCHAR *stmt = (SQLCHAR *)
    "INSERT INTO emp_photo(empno, photo_format, picture) VALUES(?, ?, ?)";
  SQLCHAR empno[10], photo_format[10];
  SQLCHAR inputParam[] = "Photo Data";
  SQLINTEGER blobInd;
  SQLCHAR fileNameBase[] = "photo1";
  SQLCHAR fileName[14] = "";
  FILE *pFile;
  SQLCHAR buffer[BUFSIZ];
  size_t n = 0;
  size_t fileSize = 0;
  SQLPOINTER valuePtr;

  printf("\n-----------------------------------------------------------");
  printf("\nUSE THE CLI FUNCTIONS\n");
  printf("  SQLSetConnectAttr\n");
  printf("  SQLAllocHandle\n");
  printf("  SQLPrepare\n");
  printf("  SQLBindParameter\n");
  printf("  SQLExecute\n");
  printf("  SQLCancel\n");
  printf("  SQLParamData\n");
  printf("  SQLPutData\n");
  printf("  SQLEndTran\n");
  printf("  SQLFreeHandle\n");
  printf("TO WRITE BLOB DATA IN PIECES:\n");

  /* set AUTOCOMMIT OFF */
  cliRC = SQLSetConnectAttr(hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            (SQLPOINTER)SQL_AUTOCOMMIT_OFF,
                            SQL_NTS);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Transactions enabled.\n");

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Prepare the statement\n");
  printf("    INSERT INTO emp_photo(empno, photo_format, picture) ");
  printf("VALUES(?, ?, ?)\n");

  /* prepare the statement */
  cliRC = SQLPrepare(hstmt, stmt, SQL_NTS);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  printf("\n  Bind parameters to the statement\n");

  /* bind the first parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           1,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           empno,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* bind the second parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           2,
                           SQL_PARAM_INPUT,
                           SQL_C_CHAR,
                           SQL_VARCHAR,
                           10,
                           0,
                           photo_format,
                           10,
                           NULL);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* SQL_DATA_AT_EXEC indicates that a data-at-exectuion parameter is used,
     and when the statement is executed, the actual data for the parameter
     will be sent with SQLPutData */
  blobInd = SQL_DATA_AT_EXEC;

  /* bind the third parameter to the statement */
  cliRC = SQLBindParameter(hstmt,
                           3,
                           SQL_PARAM_INPUT,
                           SQL_C_BINARY,
                           SQL_BLOB,
                           BUFSIZ,
                           0,
                           (SQLPOINTER)inputParam,
                           BUFSIZ,
                           &blobInd);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  /* ----------------write data from a *.bmp file ------------------------*/

  strcpy((char *)empno, "000240");
  strcpy((char *)photo_format, "bitmap");
  sprintf((char *)fileName, "%s.bmp", fileNameBase);
  printf("\n  Execute the prepared statement for\n");
  printf("    empno = '000240'\n");
  printf("    photo_format = 'bitmap'\n");
  printf("    fileName = %s\n", fileName);

  /* execute the statement */
  cliRC = SQLExecute(hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  if (cliRC == SQL_NEED_DATA)
  {
    pFile = fopen((char *)fileName, "rb");
    if (pFile == NULL)
    {
      printf(">---- ERROR Opening File -------");

      /* cancel the SQL_DATA_AT_EXEC state for hstmt */
      cliRC = SQLCancel(hstmt);
      STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);
    }
    else
    {
      /* get next parameter for which a data value is needed */
      cliRC = SQLParamData(hstmt, (SQLPOINTER *)&valuePtr);
      STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

      while (cliRC == SQL_NEED_DATA)
      { /* if more than 1 parameter used SQL_DATA_AT_EXEC then valuePtr would
	   have to be checked to determine which parameter needed data */
        while (feof(pFile) == 0)
        {
          n = fread(buffer, sizeof(char), BUFSIZ, pFile);

          /* passing data value for a parameter */
          cliRC = SQLPutData(hstmt, buffer, n);
          STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

          fileSize = fileSize + n;
          if (fileSize > 102400u)
          { /* BLOB column defined as 100K MAX */
            printf(">---- ERROR: File > 100K  -------");
            break;
          }
        }
        printf("\n  Written a total of %u bytes from %s\n",
               fileSize, fileName);

        /* get next parameter for which a data value is needed */
        cliRC = SQLParamData(hstmt, (SQLPOINTER *)&valuePtr);
        STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);
      }
    }
  }

  printf("\n  Rolling back the transaction...\n");

  /* end transactions on a connection */
  cliRC = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("  Transaction rolled back.\n");

  /* free the statement handle */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
  STMT_HANDLE_CHECK(hstmt, hdbc, cliRC);

  return rc;
} /* BlobWriteInPieces */

/* read a specific part of CLOB data */
int ClobReadASelectedPiece(SQLHANDLE hdbc)
{
  SQLRETURN cliRC = SQL_SUCCESS;
  int rc = 0;
  SQLHANDLE hstmtClobFetch, hstmtLocUse, hstmtLocFree;
  SQLCHAR *stmtClobSelect =
    (SQLCHAR *)"SELECT resume "
               "  FROM emp_resume "
               "  WHERE empno = '000140' AND resume_format = 'ascii'";
  SQLCHAR *stmtLocFree = (SQLCHAR *)"FREE LOCATOR ?";
  SQLINTEGER clobLoc; /* LOB locator for the piece you want to retrieve */
  SQLINTEGER pcbValue;
  SQLINTEGER clobPieceLen, clobLen;
  SQLUINTEGER clobPiecePos;
  SQLINTEGER ind;
  SQLCHAR *buffer;

  printf("\n-----------------------------------------------------------");
  printf("\nUSE THE CLI FUNCTIONS\n");
  printf("  SQLSetConnectAttr\n");
  printf("  SQLAllocHandle\n");
  printf("  SQLExecDirect\n");
  printf("  SQLBindCol\n");
  printf("  SQLFetch\n");
  printf("  SQLGetLength\n");
  printf("  SQLGetPosition\n");
  printf("  SQLGetSubString\n");
  printf("  SQLSetParam\n");
  printf("  SQLFreeHandle\n");
  printf("TO READ A SELECTED PIECE OF CLOB DATA:\n");

  /* set AUTOCOMMIT on */
  cliRC = SQLSetConnectAttr(hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            (SQLPOINTER)SQL_AUTOCOMMIT_ON,
                            SQL_NTS);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  /* --------------- fetch CLOB data --------------------------------------*/

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtClobFetch);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Directly execute the statement\n");
  printf("    SELECT resume\n");
  printf("      FROM emp_resume\n");
  printf("      WHERE empno = '000140' AND resume_format = 'ascii'\n");

  /* directly execute the statement */
  cliRC = SQLExecDirect(hstmtClobFetch, stmtClobSelect, SQL_NTS);
  STMT_HANDLE_CHECK(hstmtClobFetch, hdbc, cliRC);

  /* bind CLOB column to LOB locator */
  cliRC = SQLBindCol(hstmtClobFetch,
                     1,
                     SQL_C_CLOB_LOCATOR,
                     &clobLoc,
                     0,
                     &pcbValue);
  STMT_HANDLE_CHECK(hstmtClobFetch, hdbc, cliRC);

  printf("\n  Fetch the CLOB data (resume).\n");

  /* fetch the CLOB data */
  cliRC = SQLFetch(hstmtClobFetch);
  STMT_HANDLE_CHECK(hstmtClobFetch, hdbc, cliRC);

  if (cliRC == SQL_NO_DATA_FOUND)
  {
    printf("\n  Data not found.\n");
  }

  /* ---------------- work with the LOB locator -----------------------------*/

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtLocUse);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  printf("\n  Extract the piece of CLOB data.\n");

  /* get the length of the whole CLOB data */
  cliRC = SQLGetLength(hstmtLocUse,
                       SQL_C_CLOB_LOCATOR,
                       clobLoc,
                       &clobLen,
                       &ind);
  STMT_HANDLE_CHECK(hstmtLocUse, hdbc, cliRC);

  /* get the starting postion of the CLOB piece of data */
  cliRC = SQLGetPosition(hstmtLocUse,
                         SQL_C_CLOB_LOCATOR,
                         clobLoc,
                         0,
                         (SQLCHAR *)"Interests",
                         strlen("Interests"),
                         1,
                         &clobPiecePos,
                         &ind);
  STMT_HANDLE_CHECK(hstmtLocUse, hdbc, cliRC);

  /* allocate a buffer to read the piece of CLOB data */
  buffer = (SQLCHAR *)malloc(clobLen - clobPiecePos + 1);

  /* read the piece of CLOB data in buffer */
  cliRC = SQLGetSubString(hstmtLocUse,
                          SQL_C_CLOB_LOCATOR,
                          clobLoc,
                          clobPiecePos,
                          clobLen - clobPiecePos,
                          SQL_C_CHAR,
                          buffer,
                          clobLen - clobPiecePos + 1,
                          &clobPieceLen,
                          &ind);
  STMT_HANDLE_CHECK(hstmtLocUse, hdbc, cliRC);

  /* print the buffer */
  printf("\n  Print the piece of CLOB data.\n");
  printf("\n%s\n", buffer);

  free(buffer);

  /* ---------------- free the LOB locator ----------------------------------*/

  /* allocate a statement handle */
  cliRC = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtLocFree);
  DBC_HANDLE_CHECK(hdbc, cliRC);

  /* bind a parameter marker to a buffer or LOB locator */
  cliRC = SQLSetParam(hstmtLocFree,
                      1,
                      SQL_C_CLOB_LOCATOR,
                      SQL_CLOB_LOCATOR,
                      0,
                      0,
                      &clobLoc,
                      NULL);
  STMT_HANDLE_CHECK(hstmtLocFree, hdbc, cliRC);

  printf("\n  Free the LOB locator.\n");

  /* directly execute the statement */
  cliRC = SQLExecDirect(hstmtLocFree, stmtLocFree, SQL_NTS);
  STMT_HANDLE_CHECK(hstmtLocFree, hdbc, cliRC);

  /* ------------------ free the statement handles ---------------------------*/

  /* free handle resources */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmtClobFetch);
  STMT_HANDLE_CHECK(hstmtClobFetch, hdbc, cliRC);

  /* free handle resources */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmtLocUse);
  STMT_HANDLE_CHECK(hstmtLocUse, hdbc, cliRC);

  /* free handle resources */
  cliRC = SQLFreeHandle(SQL_HANDLE_STMT, hstmtLocFree);
  STMT_HANDLE_CHECK(hstmtLocFree, hdbc, cliRC);

  return rc;
} /* ClobReadASelectedPiece */