/*******************************************************************************
**
** Source File Name = spserver.c  
**
** Licensed Materials - Property of IBM
**
** (C) COPYRIGHT International Business Machines Corp. 2000
** All Rights Reserved.
**
** US Government Users Restricted Rights - Use, duplication or
** disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
**
**
** PURPOSE : This program demonstrates stored procedures implemented in CLI.
** 
** There are two parts to this program:
**           - the spclient executable (placed on the client)
**           - the spserver library (placed on the server)
**
** BUILDING THE SHARED LIBRARY:
** 1. Ensure the Database Manager Configuration file has the keyword KEEPDARI
** set to "no". This allows unloading shared libraries while developing stored
** procedures. You can view the file's settings by entering the command:
** "db2 get dbm cfg". You can set KEEPDARI to "no" with this command:
** "db2 update dbm cfg using KEEPDARI no".
** NOTE: Setting KEEPDARI to "no" causes a performance cost when accessing the stored 
** procedures because they have to be reloaded into memory each time they are called.
** If this is a consideration, use the KEEPDARI "yes" setting, and stop and restart
** DB2 before building the shared library, by entering "db2stop" followed by "db2start". 
** This forces DB2 to unload shared libraries and enables the build file or the makefile 
** to delete a previous version of the shared library from the "function" directory. 
** 2. To build the shared library, enter "bldclisp spserver" (UNIX & OS/2), "make 
** spserver" (UNIX), "nmake spserver" (OS/2 & Windows), or for the Microsoft Visual
** C++ compiler on Windows, enter "bldmclis spserver", or for the VisualAge C++ compiler
** on Windows, enter "bldvclis spserver".
** 3. To catalog the stored procedures in the shared library, first connect to the 
** database by entering: "db2 connect to sample".
** 4. If the stored procedures were previously cataloged for a different language, 
** uncatalog them by entering: "db2 -td@ -vf spdrop.db2".
** 5. Then, catalog the stored procedures by entering: "db2 -td@ -vf spcreate.db2".
**
** For more information about these samples see the README file.
**
** For more information on programming in CLI see the:
**     - "Building CLI Applications" section of the Application Building Guide, and the
**     - CLI Guide and Reference.
**
*******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlcli1.h>
#include <sqlca.h>
#include <sqludf.h>
#include "utilcli.h"

/* Declare structure for VARCHAR type */

struct small_varchar {
  sqlint16 length;
  char data[12];
};

/* Declare function prototypes for this stored procedure library */

SQL_API_RC SQL_API_FN outlanguage (char *);
SQL_API_RC SQL_API_FN out_param (double *, sqlint32 *, char *);
SQL_API_RC SQL_API_FN in_params (double *, double *, double *,
                                 char *, sqlint32 *, char *);
SQL_API_RC SQL_API_FN inout_param (double *inoutMedian, sqlint32 *, 
                                   char *, sqlint16 *);
SQL_API_RC SQL_API_FN one_result_set_to_caller (double *, sqlint32 *);
SQL_API_RC SQL_API_FN two_result_sets (double *, sqlint32 *);
SQL_API_RC SQL_API_FN extract_from_clob (char *, char *, sqlint32 * );
SQL_API_RC SQL_API_FN all_data_types (sqlint16 *, sqlint32 *, sqlint64 *,
    float *, double *, char *,  char *, struct small_varchar *,
    char *, char *, sqlint32 *, char *);
SQL_API_RC SQL_API_FN db2sql_example(char *, double *, sqlint16 *, char *, 
                                     char *, char *, char *);
SQL_API_RC SQL_API_FN dbinfo_example (char *, double *, char *, char *,
                                      sqlint32 *, struct sqludf_dbinfo *);
SQL_API_RC SQL_API_FN main_example (int, char **);


SQL_API_RC SQL_API_FN outlanguage (char out_lang[9]) 
{
   SQLHANDLE    henv, hdbc, hstmt ;
   SQLRETURN    rc,rc1 ;
   SQLCHAR      stmt[100];
   sqlint32   indicator;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;
    SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;

    strcpy((char*)stmt,"SELECT LANGUAGE FROM sysibm.sysprocedures ");
    strcat((char*)stmt,"WHERE procname = 'OUT_LANGUAGE' ");

    rc = SQLExecDirect( hstmt, stmt, SQL_NTS ) ;


    /* bind columns to variables */
    rc = SQLBindCol( hstmt, 1, SQL_C_CHAR, out_lang, 9, &indicator);
    STMT_HANDLE_CHECK( hstmt, rc);

    /* fetch each row, and display */
    rc = SQLFetch( hstmt );
    STMT_HANDLE_CHECK( hstmt, rc);

    if(rc != SQL_SUCCESS) return (0);

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);
} /* end outlanguage function */


  char buffer[33];

SQL_API_RC SQL_API_FN out_param(double *outMedianSalary,
                 sqlint32 *out_sqlcode, char buffer[33])
{
   sqlint16       num_records;
   double      medianSalary;
   int counter = 0;
   SQLHANDLE   henv, hdbc, hstmt ;
   SQLHANDLE   hstmt1 ;
   SQLRETURN   rc, rc1 ;
   SQLCHAR     stmt[100];
   SQLCHAR     stmt1[100];
   sqlint32  indicator;
   struct sqlca  sqlca;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt1 ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy((char*)stmt,"SELECT CAST(salary AS DOUBLE)  FROM staff ");
    strcat((char*)stmt,"order by salary");
    
    strcpy((char*)stmt1,"SELECT count(*)  FROM staff ");

    rc = SQLExecDirect( hstmt1, stmt1, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecDirect( hstmt, stmt, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy(buffer, "SQLExec");

    /* bind columns to variables */
    rc = SQLBindCol( hstmt1, 1, SQL_C_SHORT, &num_records , 0, NULL);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLBindCol( hstmt, 1, SQL_C_DOUBLE, &medianSalary , 0, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    /* fetch rowno.   */
    rc = SQLFetch( hstmt1 );

    if( rc != SQL_SUCCESS || rc == SQL_NO_DATA_FOUND) 
    {
      rc1 = SQLGetSQLCA(henv, hdbc, hstmt1, &sqlca);

      *out_sqlcode = SQLCODE;  
      return (0);
    }
    /* while (counter < (num_records / 2 + 1)) { */
    for(counter=0; rc == SQL_SUCCESS && counter < (num_records/2+1); 
        counter++)
    rc = SQLFetch( hstmt );

    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "FETCH");
    /* Set value of OUT parameter to host variable */
    *outMedianSalary = medianSalary;
    

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt1 ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);

} /* end out_param function */


  char department[4];

SQL_API_RC SQL_API_FN in_params (double *inlowsal, 
    double *inmedsal,
    double *inhighsal,
    char department[4],
    sqlint32 *out_sqlcode, char buffer[33])
{
    double       lowsal;
    double       medsal;
    double       highsal;
    double       salary;
    double       tmp;

    SQLHANDLE    henv, hdbc, hstmt ;
    SQLHANDLE    hstmt1 ;
    SQLRETURN    rc,rc1 ;
    SQLCHAR      stmt[100];
    SQLCHAR      stmt1[100];
    sqlint32   indicator;
    struct sqlca sqlca;
    SQLCHAR      cursor[20];
    SQLSMALLINT  clength ;

    lowsal  = *inlowsal;
    medsal  = *inmedsal;
    highsal = *inhighsal;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/
    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt1 ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    /* set AUTOCOMMIT off or on */
    rc = SQLSetConnectAttr( hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            SQL_AUTOCOMMIT_OFF, SQL_NTS) ;


    strcpy((char*)stmt,"SELECT CAST(salary AS DOUBLE)  FROM EMPLOYEE ");
    strcat((char*)stmt,"WHERE workdept = ? FOR UPDATE OF salary");

    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_CHAR,
                         SQL_CHAR,0,
                         0, department,
                         4, NULL);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecute(hstmt);

    /* bind columns to variables */

    rc = SQLBindCol( hstmt, 1, SQL_C_DOUBLE, &salary , 0, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);


    /* Get Cursor of the SELECT statement's handle */
    rc = SQLGetCursorName( hstmt, cursor, 20, &clength ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    sprintf((char *)stmt1,
            "UPDATE EMPLOYEE set salary = ?  where current of %s ",
            cursor);

    rc = SQLPrepare(hstmt1, stmt1, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* fetch rowno.   */
    rc = SQLFetch( hstmt );
    strcpy(buffer, "FETCH (1)");
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    if ( rc != SQL_SUCCESS ) return (0);

    while( rc == SQL_SUCCESS)
    {
      if (salary < lowsal) 
      {
	rc = SQLBindParameter(hstmt1, 1,
			     SQL_PARAM_INPUT, SQL_C_DOUBLE,
			     SQL_DOUBLE,0,
			     0, &lowsal,
			     0, NULL);
	rc = SQLExecute(hstmt1);
	strcpy(buffer, "UPDATE (1)");
	if ( rc != SQL_SUCCESS ) return (0);
      }
      else if (salary < medsal )
      {
	rc = SQLBindParameter(hstmt1, 1,
			     SQL_PARAM_INPUT, SQL_C_DOUBLE,
			     SQL_DOUBLE,0,
			     0, &medsal,
			     0, NULL);
	rc = SQLExecute(hstmt1);
	strcpy(buffer, "UPDATE (2)");
	if ( rc != SQL_SUCCESS ) return (0);
      }
      else if (salary < highsal )  
      {
	rc = SQLBindParameter(hstmt1, 1,
			     SQL_PARAM_INPUT, SQL_C_DOUBLE,
			     SQL_DOUBLE,0,
			     0, &highsal,
			     0, NULL);
	rc = SQLExecute(hstmt1);
	strcpy(buffer, "UPDATE (3)");
	if ( rc != SQL_SUCCESS ) return (0);
      }

      else   
      {
	tmp=salary*1.1; 
	rc = SQLBindParameter(hstmt1, 1,
			     SQL_PARAM_INPUT, SQL_C_DOUBLE,
			     SQL_DOUBLE,0,
			     0, &tmp,
			     0, NULL);
	rc = SQLExecute(hstmt1);
	rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
	*out_sqlcode = SQLCODE;  
	strcpy(buffer, "UPDATE (4)");
	if ( rc != SQL_SUCCESS ) return (0);
      }

      rc = SQLFetch( hstmt );
      rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
      *out_sqlcode = SQLCODE;  
      strcpy(buffer, "FETCH (2)");
      if ( rc == SQL_ERROR ) return (0);

    }
    if(SQLCODE == 100) *out_sqlcode =0;

    strcpy(buffer, "RETURN 1");

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt1 ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);
} /* end in_params function */


SQL_API_RC SQL_API_FN inout_param (double *inoutMedian,
                sqlint32 *out_sqlcode, char buffer[33],
                sqlint16 nullinds[3])
{
   sqlint16     num_records;
   double       medianSalary;
   double       tmpsalary;
   int          counter = 0;
   SQLHANDLE    henv, hdbc, hstmt ;
   SQLHANDLE    hstmt1 ;
   SQLRETURN    rc,rc1 ;
   SQLCHAR      stmt[100];
   SQLCHAR      stmt1[100];
   sqlint32   indicator;
   struct sqlca sqlca;

   medianSalary = *inoutMedian;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    if (nullinds[0] < 0) {
      /* NULL value was received as input, so return NULL output */
      nullinds[0] = -1;
      nullinds[1] = -1;
      nullinds[2] = -1;
      return 0;
    }

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt1 ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy((char*)stmt,"SELECT CAST(salary AS DOUBLE)  FROM staff ");
    strcat((char*)stmt,"where salary > ? order by salary ");
    
    strcpy((char*)stmt1,"SELECT count(*)  FROM staff ");
    strcat((char*)stmt1,"WHERE salary > ? ");


    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLPrepare(hstmt1, stmt1, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_DOUBLE,
                         SQL_DOUBLE,0,
                         0, &medianSalary,
                         0, NULL);
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLBindParameter(hstmt1, 1,
                         SQL_PARAM_INPUT, SQL_C_DOUBLE,
                         SQL_DOUBLE,0,
                         0, &medianSalary,
                         0, NULL);
    if ( rc != SQL_SUCCESS ) return (0);
    strcpy(buffer, "inout_param");

    rc = SQLExecute(hstmt);
    if ( rc != SQL_SUCCESS ) return (0);

    /* bind columns to variables */
    rc = SQLBindCol( hstmt, 1, SQL_C_DOUBLE, &tmpsalary , 0, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLBindCol( hstmt1, 1, SQL_C_SHORT, &num_records, 0,&indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecute(hstmt1);
    if ( rc != SQL_SUCCESS ) 
    {
      rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
      *out_sqlcode = SQLCODE;  
      return (0);
    }

    /* fetch rowno.   */
    rc = SQLFetch( hstmt1 );

    strcpy(buffer, "SQLExec");


    for(counter=0; rc == SQL_SUCCESS && counter < (num_records/2+1); counter++)
    {
      rc = SQLFetch( hstmt );
    }

    /* Set value of INOUT parameter to median salary */
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *inoutMedian = tmpsalary;
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "FETCH ");
    
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt1 ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);

} /* end inout_param function */

    double l_insalary;

SQL_API_RC SQL_API_FN one_result_set_to_caller (double *insalary,
                                          sqlint32 *out_sqlcode)
{
   double        medianSalary;
   int counter   = 0;
   SQLHANDLE     henv, hdbc, hstmt ;
   SQLRETURN     rc,rc1 ;
   SQLCHAR       stmt[100];
   struct sqlca  sqlca;


   l_insalary = *insalary;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy((char*)stmt,"SELECT name, job, CAST(salary AS DOUBLE) AS salary");
    strcat((char*)stmt," FROM staff WHERE salary > ? ORDER BY salary");
    
    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_DOUBLE,
                         SQL_DOUBLE,0,
                         0, &l_insalary,
                         0, NULL);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecute(hstmt);
    if ( rc != SQL_SUCCESS ) return (0);

    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    /* test fetch  */
    rc = SQLFetch( hstmt );
    if ( rc != SQL_SUCCESS ) return (0);
   
    if (rc == SQL_ERROR)
    {
      rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    }

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;

    rc = SQLDisconnect( hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    return (0);
} /* end one_result_set_to_caller function */

SQL_API_RC SQL_API_FN two_result_sets (double *inMedianSalary,
                                        sqlint32 *out_sqlcode)
{
   SQLHANDLE    henv, hdbc, hstmt ;
   SQLHANDLE hstmt1,hstmt2 ;
   SQLRETURN rc,rc1 ;
   SQLCHAR  stmt[100];
   SQLCHAR  stmt1[150];
   struct sqlca  sqlca;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt1 ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt2 ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    /* Statement for first result set:
       staff with a salary greater than the IN parameter */
    strcpy((char*)stmt,"SELECT name, job, CAST(salary AS DOUBLE) AS salary");
    strcat((char*)stmt," FROM staff WHERE salary > ? ORDER BY salary");

    /* Statement for first result set:
       staff with a salary less than the IN parameter */
    strcpy((char*)stmt1,"SELECT name, job, CAST(salary AS DOUBLE) AS salary");
    strcat((char*)stmt1," FROM staff WHERE salary < ? ");
    strcat((char*)stmt1,"ORDER BY salary DESC");
    
    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLPrepare(hstmt1, stmt1, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_DOUBLE,
                         SQL_DOUBLE,0,
                         0, inMedianSalary,
                         0, NULL);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLBindParameter(hstmt1, 1,
                         SQL_PARAM_INPUT, SQL_C_DOUBLE,
                         SQL_DOUBLE,0,
                         0, inMedianSalary,
                         0, NULL);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecute(hstmt);
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecute(hstmt1);
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt1, &sqlca);
    *out_sqlcode = SQLCODE;  

    return (0);

} /* end two_result_sets function */

SQL_API_RC SQL_API_FN all_data_types (sqlint16 *smallInOut,
    sqlint32 *intInOut, sqlint64 *bigInOut, 
    float *realInOut, double *doubleInOut,
    char charOut[2], char charsOut[16], struct small_varchar *varcharOut,
    char dateOut[11], char timeOut[9], sqlint32 *out_sqlcode,
    char buffer[33])
{

   SQLHANDLE     henv, hdbc, hstmt ;
   SQLHANDLE     hstmt1, hstmt2, hstmt3, hstmt4;

   SQLCHAR       stmt[100];
   SQLCHAR       stmt1[100];
   SQLCHAR       stmt2[100];
   char firstnme[13];        /* VARCHAR(12) */
   SQLRETURN     rc,rc1 ;
   sqlint32    indicator;
   struct sqlca  sqlca;

   if (*smallInOut == 0) { *smallInOut = 1; }
   else { *smallInOut = (*smallInOut / 2); }

   if (*intInOut == 0) { *intInOut = 1; }
   else { *intInOut = (*intInOut / 2); }

   if (*bigInOut == 0) { *bigInOut = 1; }
   else { *bigInOut = (*bigInOut / 2); }

   if (*realInOut == 0) { *realInOut = 1; }
   else { *realInOut = (*realInOut / 2); }

   if (*doubleInOut == 0) { *doubleInOut = 1; }
   else { *doubleInOut = (*doubleInOut / 2); }

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt1 ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt2 ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt3 ) ;
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt4 ) ;
    if ( rc != SQL_SUCCESS ) return (0);


    strcpy((char*)stmt,"SELECT midinit from employee  ");
    strcat((char*)stmt,"WHERE empno = '000180'");
    strcpy((char*)stmt1,"SELECT lastname from employee  ");
    strcat((char*)stmt1,"WHERE empno = '000180'");
    strcpy((char*)stmt2,"SELECT firstnme from employee  ");
    strcat((char*)stmt2,"WHERE empno = '000180'");
    
    rc = SQLExecDirect( hstmt, stmt, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecDirect( hstmt1, stmt1, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);


    strcpy(buffer, "SQLExec");

    /* bind columns to variables */
    rc = SQLBindCol( hstmt, 1, SQL_C_CHAR, charOut , 2, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);
 
    rc = SQLBindCol( hstmt1, 1, SQL_C_CHAR, charsOut , 16, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "SELECT midinit");
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt1 );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt1, &sqlca);
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "SELECT LASTNAME");
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLExecDirect( hstmt2, stmt2, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLBindCol( hstmt2, 1, SQL_C_CHAR, firstnme, 13, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt2 );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt2, &sqlca);
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "SELECT FIRSTNAME");
    if ( rc != SQL_SUCCESS ) return (0);

    /* Set the length field of the VARCHAR struct          */
    varcharOut->length = strlen(firstnme);

    /* Copy the data from firstnme into the data field
       of the VARCHAR struct                               */
    memcpy(varcharOut->data, (char *)firstnme, varcharOut->length);

    strcpy((char*)stmt,"values CURRENT DATE  ");
    strcpy((char*)stmt1,"values CURRENT TIME  ");

    rc = SQLExecDirect( hstmt3, stmt, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLBindCol( hstmt3, 1, SQL_C_CHAR, dateOut , 11, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt3 );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt3, &sqlca);
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "VALUES CURRENT DATE");
    if ( rc != SQL_SUCCESS ) return (0);


    rc = SQLExecDirect( hstmt4, stmt1, SQL_NTS) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLBindCol( hstmt4, 1, SQL_C_CHAR, timeOut , 9, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt4 );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt4, &sqlca);
    *out_sqlcode = SQLCODE;  
    strcpy(buffer, "VALUES CURRENT TIME");
    if ( rc != SQL_SUCCESS ) return (0);


    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt1 ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt2 ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt3 ) ;
    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt4 ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);


} /* end all_data_types procedure */


SQL_API_RC SQL_API_FN dbinfo_example (
  char injob[9],       /* Input  - CHAR(8)                           */ 
  double *salary,      /* Output - DOUBLE                            */
  char dbname[129],    /* Output - database name from DBINFO         */
  char dbversion[9],   /* Output - database version from DBINFO      */
  sqlint32 *out_sqlcode,
  struct sqludf_dbinfo *dbinfo  /* Pointer to DBINFO structure        */
) {

   int          counter = 0;
   SQLHANDLE    henv, hdbc, hstmt ;
   SQLRETURN    rc,rc1 ;
   SQLCHAR      stmt[100];
   sqlint32     indicator;
   struct sqlca sqlca;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLCODE = 0;

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy((char*)stmt,"SELECT AVG(salary) FROM employee WHERE job = ?");

    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_CHAR,
                         SQL_CHAR,0,
                         0, injob,
                         9, NULL);
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLExecute(hstmt);
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    if ( rc != SQL_SUCCESS ) return (0);


    /* bind columns to variables */
    rc = SQLBindCol( hstmt, 1, SQL_C_DOUBLE, salary , 0, &indicator);
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    
    strcpy (dbname, (char *)(dbinfo->dbname));
    strcpy (dbversion, (char *)(dbinfo->ver_rel));

    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);

} /* end dbinfo_example function */


SQL_API_RC SQL_API_FN main_example ( int argc, char **argv)
{
   char         injob[9];    
   double      *salary=NULL;     

   int          counter = 0;
   SQLHANDLE    henv, hdbc, hstmt ;
   SQLRETURN    rc,rc1 ;
   SQLCHAR      stmt[100];
   sqlint32     indicator;
   struct sqlca sqlca;

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    strcpy (injob, (char *)argv[1]); 

    SQLCODE = 0;
    salary  = (double  * ) malloc ( sizeof (double));

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy((char*)stmt,"SELECT AVG(salary) FROM employee WHERE job = ?");

    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_CHAR,
                         SQL_CHAR,0,
                         0, injob,
                         9, NULL);
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLExecute(hstmt);
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    memcpy ((sqlint32 *)argv[3], (sqlint32 *)&SQLCODE, sizeof(sqlint32));
    if ( rc != SQL_SUCCESS ) return (0);


    /* bind columns to variables */
    rc = SQLBindCol( hstmt, 1, SQL_C_DOUBLE, salary , 0, &indicator);

    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt );

    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    memcpy ((sqlint32 *)argv[3], (sqlint32 *)&SQLCODE, sizeof(sqlint32));
    if ( rc != SQL_SUCCESS ) return (0);
    memcpy ((double *)argv[2], (double *)salary, sizeof(double));
    memcpy ((sqlint32 *)argv[3], (sqlint32 *)&SQLCODE, sizeof(sqlint32));

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);

} /* end main_example function */

  
SQL_API_RC SQL_API_FN db2sql_example (
  char injob[9],         /* Input - CHAR(8)                            */ 
  double *salary,        /* Output - DOUBLE                            */
  sqlint16 nullinds[2],  /* Inout - Array[n] of null indicators where  */
                         /* n = number of parameters declared by user  */
  char sqlst[6],         /* Output - SQLSTATE as CHAR(5)               */
  char qualname[28],     /* Input - qualified name as CHAR(27)         */
  char specname[19],     /* Input - specific name as CHAR(18)          */
  char diagmsg[71]       /* Output - diagnostic message as CHAR(70)    */
) 
{
   int          counter = 0;
   SQLHANDLE    henv, hdbc, hstmt ;
   SQLRETURN    rc,rc1 ;
   SQLCHAR      stmt[100];
   sqlint32     indicator;
   struct sqlca sqlca;
   sqlint32    *out_sqlcode=NULL;

   out_sqlcode  = (sqlint32 *) malloc ( sizeof (sqlint32));
   *salary      = 0;

   if (nullinds[0] < 0)
   {
     /* NULL value was received as input, so return NULL output */
     /* Using the RETURNS NULL ON NULL CALL clause in your
     CREATE PROCEDURE statement is more efficient */
     nullinds[1] = -1;

     /* Set custom SQLSTATE to return to client. */
     strcpy(sqlst, "38100");

     /* Set custom message to return to client. Note that although the
     OUT parameter is declared as CHAR(70), DB2 prepends the
     procedure name and shared library entry point to the message.
     Keep the custom message short to avoid truncation. */
     strcpy(diagmsg, "Received null input.");

     return (0);
   }

   /*-----------------------------------------------------------------*/
   /* Setup CLI required environment                                  */
   /*-----------------------------------------------------------------*/

   rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
   if ( rc != SQL_SUCCESS ) return (0);
   rc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
   if ( rc != SQL_SUCCESS ) return (0);

   /*-----------------------------------------------------------------*/
   /* Issue NULL Connect, since in CLI we need a statement handle     */
   /* and thus a connection handle and environment handle.            */
   /* A connection is not established, rather the current             */
   /* connection from the calling application is used                 */
   /*-----------------------------------------------------------------*/

    SQLConnect( hdbc, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS ) ;

    rc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    strcpy((char*)stmt,"SELECT (CAST(AVG(salary) AS DOUBLE)) FROM employee "); 
    strcat((char*)stmt,"where job = ?"); 

    rc = SQLPrepare(hstmt, stmt, SQL_NTS);
    if ( rc != SQL_SUCCESS ) return (0);

    /* Bind the parameter to application variables () */
    rc = SQLBindParameter(hstmt, 1,
                         SQL_PARAM_INPUT, SQL_C_CHAR,
                         SQL_CHAR,0,
                         0, injob,
                         9, NULL);
    if ( rc != SQL_SUCCESS ) return (0);
    rc = SQLExecute(hstmt);
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  

    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    /* bind columns to variables */
    rc = SQLBindCol( hstmt, 1, SQL_C_DOUBLE, salary , 0, &indicator);
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFetch( hstmt );
    rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
    *out_sqlcode = SQLCODE;  
    if ( rc != SQL_SUCCESS ) return (0);

    rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLDisconnect( hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;

    rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
    return (0);

} /* end db2sql_example function */