/****************************************************************************
** (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: spclient.sqC
**
** SAMPLE: Call the set of stored procedues implemented in spserver.sqC
**
**         This file contains eight functions that call stored procedures:
**
**  (1) callOutLanguage: Calls a stored procedure that returns the 
**      implementation language of the stored procedure library
**        Parameter types used: OUT CHAR(8)
**  (2) callOutParameter: Calls a stored procedure that returns median 
**      salary of employee salaries
**        Parameter types used: OUT DOUBLE                    
**  (3) callInParameters: Calls a stored procedure that accepts 3 salary 
**      values and updates employee salaries in the EMPLOYEE table based 
**      on these values for a given department.
**        Parameter types used: IN DOUBLE
**                              IN DOUBLE
**                              IN DOUBLE
**                              IN CHAR(3)
**  (4) callInoutParameter: Calls a stored procedure that accepts an input
**      value and returns the median salary of those employees in the
**      EMPLOYEE table who earn more than the input value. Demonstrates how 
**      to use null indicators in a client application. The stored procedure
**      has to be implemented in the following parameter styles for it to be
**      compatible with this client application.
**        Parameter style for a C stored procedure: SQL
**        Parameter style for a Java(JDBC/SQLJ) stored procedure: JAVA
**        Parameter style for an SQL stored procedure: SQL
**        Parameter types used: INOUT DOUBLE
**  (5) callClobExtract: Calls a stored procedure that extracts and returns a 
**      portion of a CLOB data type
**        Parameter types used: IN CHAR(6)
**                              OUT VARCHAR(1000)
**  (6) callDBINFO: Calls a stored procedure that receives a DBINFO
**      structure and returns elements of the structure to the client
**        Parameter types used: IN CHAR(8)
**                              OUT DOUBLE
**                              OUT CHAR(128)
**                              OUT CHAR(8)
**  (7) callProgramTypeMain: Calls a stored procedure implemented with
**       PROGRAM TYPE MAIN parameter style
**         Parameter types used: IN CHAR(8)
**                               OUT DOUBLE
**  (8) callAllDataTypes: Calls a stored procedure that uses a variety of 
**      common data types (not DECIMAL, GRAPHIC, VARGRAPHIC, BLOB, CLOB, DBCLOB).
**      This sample shows only a subset of DB2 supported data types. For a  
**      full listing of DB2 data types, please see the SQL Reference.
**        Parameter types used: INOUT SMALLINT
**                              INOUT INTEGER
**                              INOUT BIGINT
**                              INOUT REAL
**                              INOUT DOUBLE
**                              OUT CHAR(1)
**                              OUT CHAR(15)
**                              OUT VARCHAR(12)
**                              OUT DATE
**                              OUT TIME
**
**         The file "utilemb.sqC" contains functions for error-checking and
**         rolling back a transaction in case of error. This file must be
**         compiled and its object file linked to the "spclient" program.
**
** SQL STATEMENTS USED:
**         CALL
**         CONNECT
**         ROLLBACK
**         SELECT
**
** STRUCTURES USED:
**         sqlca
**         sqlda
**
** EXTERNAL DEPENDENCIES:
**      For successful precompilation, the sample database must exist 
**      (see DB2's db2sampl command).
**      The stored procedures called from this program must have been built
**      and cataloged in the database (see the instructions in spserver.sqC).
**      This program must have been precompiled (see DB2's PREPARE command).
**      The packages associated with this program must be bound to the 
**      database (see DB2's BIND command). 
**      This program must have been compiled and linked with the supported 
**      compiler and linker for the current environment.
**
**                           spclient           spclient          
*****************************************************************************
**
** For more information on the sample programs, see the README file.
**
** For information on developing embedded SQL applications see the Developing Embedded SQL Applications book.
**
** For information on using SQL statements, see the SQL Reference.
**
** For the latest information on programming, compiling, and running DB2
** applications, visit the DB2 Information Center at
**       http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp
****************************************************************************/

#include <string.h>
#include <sqlenv.h>
#include <sqlda.h>
#include <sqlca.h>
#include <stdio.h>
#include "utilemb.h"
#if ((__cplusplus >= 199711L) && !defined DB2HP && !defined DB2AIX) || \
    (DB2LINUX && (__LP64__ || (__GNUC__ >= 3)))
   #include <iomanip>
   #include <iostream>
   using namespace std; 
#else
   #include <iomanip.h>
   #include <iostream.h>
#endif

struct sqlca sqlca = { 0 };

class Spclient
{
  public:
    int Call_StorProcs();
    int callOutLanguage(char *);
    double callOutParameter();
    int callInParameters(double, double, double, char *);
    int callInoutParameter(double);
    int callClobExtract(char *);
    int callAllDataTypes();
    int callDBINFO(char *);
    int callProgramTypeMain(char *);
    
  private:
    EXEC SQL BEGIN DECLARE SECTION;
      // declare host variables for connecting to the database
      char database[9];
      char userid[9];
      char passwd[19];
    EXEC SQL END DECLARE SECTION;
};

int Spclient::Call_StorProcs()
{
  // declare variables
  char outLang[9];
  int testLangC;
  int testLangJava;
  int testLangSQL;
  double median;

  callOutLanguage(outLang);
  // we assume that all the remaining stored procedures are also written in
  // the same language as outLang and set the following variables accordingly.
  // This would help us in invoking only those stored procedures that are 
  // supported in that particular language.
  testLangSQL = strncmp(outLang, "SQL", 3);
  testLangC = strncmp(outLang, "C", 1);
  testLangJava = strncmp(outLang, "JAVA", 4);

  median = callOutParameter();
  callInParameters(15000, 20000, 25000, "E11");
    
  // call INOUT_PARAM stored procedure                      
  cout << "\nCALL stored procedure named INOUT_PARAM" << endl;
  cout << "using the median returned by the call to OUT_PARAM" << endl;
  callInoutParameter(median);

  // call INOUT_PARAM stored procedure two more times to          
  // intentionally show 2 different errors.  The first error is
  // a user-defined error that is returned when an invalid  parameter
  // value (value less than 0 not valid in the logic context) is passed
  // to the procedure.  The second error shown is the result of a
  // NOT FOUND error that is raised when no rows are found to satisfy
  // a query in the procedure.  No row is found because the query
  // depends on the procedure's input parameter value which is too high.
  cout << "\nCALL stored procedure INOUT_PARAM again" << endl;
  cout << "using a NULL input value" << endl;
  cout << "\n-- The following error report is expected! --" << endl;
  callInoutParameter(-99999);

  cout << "\nCALL stored procedure INOUT_PARAM again \n";
  cout << "using a value that returns a NOT FOUND error from the ";
  cout << "stored procedure\n";
  cout << "\n-- The following error report is expected! --" << endl;
  callInoutParameter(99999.99);
  
  if (testLangC == 0)
  {
    // warn the user that the CLI stored procedure
    // requires a change to the UDF_MEM_SZ variable
    cout << "\n  If the CLOB EXTRACT stored procedure is implemented\n"
         << "  using CLI, you must increase the value of the UDF_MEM_SZ\n"
         << "  database manager configuration variable to at least two\n"
         << "  pages larger than the size of the input arguments and\n"
         << "  the result of the stored procedure. To do this, issue\n"
         << "  the following command from the CLP:\n"
         << "    db2 UPDATE DBM CFG USING UDF_MEM_SZ 2048\n"
         << "  For the change to take effect, you must then stop and\n"
         << "  restart the DB2 server by issuing the following\n"
         << "  commands from the CLP:\n"
         << "    db2stop\n" << "    db2start" << endl;
  }
  callClobExtract("000140");

  if (testLangC != 0)
  {
    // stored procedures of PROGRAM TYPE MAIN or those containing
    // the DBINFO clause can only be implemented with
    // LANGUAGE C stored procedures. If outLang != "C",
    // since there is no corresponding sample, we do nothing.
  }
  else
  {
    callDBINFO("MANAGER");
    callProgramTypeMain("DESIGNER");
  }
  
  //*************************************************************************
  // Embedded C/C++ applications do not provide direct support for the DECIMAL  
  // data type.
  // The following programming languages can be used to directly manipulate 
  // the DECIMAL type: 
  //          - JDBC
  //          - SQLJ
  //          - SQL routines
  //          - .NET common language runtime languages (C#, Visual Basic)
  // Please see the SpClient implementation for one of the above languages
  // to see this functionality.
  //*************************************************************************

  callAllDataTypes();
  
  //*************************************************************************
  // Embedded C/C++ client applications do not support receiving result sets 
  // from stored procedures.
  // The following programming languages can be used to recieve result sets 
  // from stored procedures: 
  //          - CLI 
  //          - JDBC
  //          - SQLJ
  //          - SQL routines
  //          - .NET common language runtime languages (C#, Visual Basic)
  // Please see the SpClient implementation for one of the above languages
  // to see this functionality.
  //*************************************************************************

  // rollback any changes to the database made by this sample
  EXEC SQL ROLLBACK;
  EMB_SQL_CHECK("ROLLBACK");
  cout << "\nStored procedure rolled back" << endl;

  // disconnect from Remote Database
  EXEC SQL CONNECT RESET;
  EMB_SQL_CHECK("CONNECT RESET");

  return (0);
} // Spclient::Call_StorProcs

int Spclient::callOutLanguage(char *language)
{
  /********************************************************\
  * Call OUT_LANGUAGE stored procedure                     *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    char outOutLangLanguage[9]; // host variable naming convention:
                                // <param_mode><stored_proc_name><var_name>
    sqlint16 outOutLangLanguageInd;
  EXEC SQL END DECLARE SECTION;

  cout << "\nCALL stored procedure named OUT_LANGUAGE " << endl;

  outOutLangLanguageInd = -1;

  EXEC SQL CALL OUT_LANGUAGE(:outOutLangLanguage:outOutLangLanguageInd);
  EMB_SQL_CHECK("CALL OUT_LANGUAGE");

  if (outOutLangLanguageInd == 0)
  {
    /********************************************************\
    * Display the language of the stored procedures          *
    \********************************************************/

    strcpy(language, outOutLangLanguage);

    cout << "Stored procedures are implemented in LANGUAGE "
         << language << endl;
  }
  
  return (0);
} // Spclient::callOutLanguage

double Spclient::callOutParameter()
{
  /********************************************************\
  * Call OUT_PARAM stored procedure                        *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    double outOutParamMedian;
    sqlint16 outOutParamMedianInd;
  EXEC SQL END DECLARE SECTION;

  cout << "\nCALL stored procedure named OUT_PARAM " << endl;
  
  // initialize variables
  outOutParamMedian = -1; 
  outOutParamMedianInd = -1;
    
  // OUT_PARAM is of parameter style SQL, so pass a null indicator
  EXEC SQL CALL OUT_PARAM(:outOutParamMedian:outOutParamMedianInd);
  EMB_SQL_CHECK("CALL OUT_PARAM");
  
  if (outOutParamMedianInd == 0)
  {
    cout << "Stored procedure returned successfully" << endl;

    /***********************************************************\
    * Display the median salary returned as an output parameter *
    \***********************************************************/

    cout << "Median salary returned from OUT_PARAM = "
         << setw(8) << outOutParamMedian << endl;
  }
     
  return outOutParamMedian;
} // Spclient::callOutParameter

int Spclient::callInParameters(double lowsal,
                               double medsal,
                               double highsal,
                               char *dept)
{
  /********************************************************\
  * Call IN_PARAMS stored procedure                        *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    // declare host variables for passing data to IN_PARAMS
    double inInParamLowSal;
    double inInParamMedSal;
    double inInParamHighSal;
    char inInParamDept[4];
    // declare NULL indicators for each parameter
    sqlint16 inInParamLowSalInd;
    sqlint16 inInParamMedSalInd;
    sqlint16 inInParamHighSalInd;
    sqlint16 inInParamDeptInd;
    // declare host variables for showing results of IN_PARAMS
    double hvInParamDeptSumSalary;
  EXEC SQL END DECLARE SECTION;
  
  // set the input parameters of the stored procedure      
  strcpy(inInParamDept, dept);
  inInParamLowSal = lowsal;
  inInParamMedSal = medsal;
  inInParamHighSal = highsal;
  inInParamDeptInd = 0;
  inInParamLowSalInd = 0;
  inInParamMedSalInd = 0;
  inInParamHighSalInd = 0;
  
    
  EXEC SQL SELECT SUM(salary) INTO :hvInParamDeptSumSalary
    FROM employee
    WHERE workdept = :inInParamDept;
  EMB_SQL_CHECK("SUM BEFORE");

  cout << "\nSum of salaries for dept. " << inInParamDept << " = "
       << setw(8) << hvInParamDeptSumSalary << " before calling IN_PARAMS " << endl;
  cout << "CALL stored procedure named IN_PARAMS " << endl;

  // IN_PARAMS is of parameter style SQL, so pass null indicators
  EXEC SQL CALL IN_PARAMS(:inInParamLowSal:inInParamLowSalInd,
                          :inInParamMedSal:inInParamMedSalInd,
                          :inInParamHighSal:inInParamHighSalInd,
                          :inInParamDept:inInParamDeptInd);
  EMB_SQL_CHECK("CALL IN_PARAMS");

  // check that the stored procedure executed successfully
  if (sqlca.sqlcode == 0)
  {
    cout << "Stored procedure returned successfully" << endl;

    /********************************************************\
    * Display the sum salaries for the affected department   *
    \********************************************************/

    EXEC SQL SELECT SUM(salary) INTO :hvInParamDeptSumSalary
      FROM employee
      WHERE workdept =:inInParamDept;
    EMB_SQL_CHECK("SUM AFTER");

    cout << "Sum of salaries for dept. " << inInParamDept << " = "
         << setw(8) << hvInParamDeptSumSalary << " after calling IN_PARAMS "
         << endl;
  }
 
  return (0);
} // Spclient::callInParameters

int Spclient::callInoutParameter(double median)
{
  /********************************************************\
  * Call INOUT_PARAM stored procedure                      *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    double inoutInOutParamMedian;
    sqlint16 inoutInOutParamMedianInd;
  EXEC SQL END DECLARE SECTION;

  if (median < 0)
  {
    // salary was negative, indicating a probable error,
    // so pass a null value to the stored procedure instead
    // by setting inoutInOutParamMedianInd to a negative value
    inoutInOutParamMedianInd = -1;
  }
  else
  {
    // salary was positive, so pass the value of median
    // to the stored procedure by setting inoutInOutParamMedianInd to 0
    inoutInOutParamMedian = median;
    inoutInOutParamMedianInd = 0;
  }

  // INOUT_PARAM is of parameter style SQL, so pass null indicators
  EXEC SQL CALL INOUT_PARAM(:inoutInOutParamMedian:inoutInOutParamMedianInd);
  EMB_SQL_CHECK("CALL INOUT_PARAM");

  // check that the stored procedure executed successfully
  if (sqlca.sqlcode == 0 && inoutInOutParamMedianInd == 0)
  {
    cout << "Stored procedure returned successfully" << endl;
    cout << "Median salary returned from INOUT_PARAM = "
         << setw(8) << inoutInOutParamMedian << endl;
  }  

  return (0);
} // Spclient::callInoutParameter

int Spclient::callClobExtract(char *empno)
{
  /********************************************************\
  * Call CLOB_EXTRACT stored procedure                     *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    // declare host variables for passing data to CLOB_EXTRACT
    char inExtFromClobEmpNum[7];
    char outExtFromClobResume[1001];
    // declare NULL indicators for each parameter
    sqlint16 inExtFromClobEmpNumInd;
    sqlint16 outExtFromClobResumeInd;
  EXEC SQL END DECLARE SECTION;
  
  if (empno == NULL)
  {
    inExtFromClobEmpNumInd = -1;
  }
  else
  {
    inExtFromClobEmpNumInd = 0;
    strcpy(inExtFromClobEmpNum, empno);
  }
  
  cout << "\nCALL stored procedure named CLOB_EXTRACT " << endl;

  // CLOB_EXTRACT is of parameter style SQL, so pass null indicators
  EXEC SQL CALL CLOB_EXTRACT(:inExtFromClobEmpNum:inExtFromClobEmpNumInd, 
                             :outExtFromClobResume:outExtFromClobResumeInd);
  EMB_SQL_CHECK("CALL CLOB_EXTRACT");

  // check that the stored procedure executed successfully
  if (sqlca.sqlcode == 0 && outExtFromClobResumeInd == 0)
  {
    cout << "Stored procedure returned successfully" << endl;
    cout << "Resume section returned from CLOB_EXTRACT = \n"
         << outExtFromClobResume << endl;
  }
  else
  {
    // print the error message
    cout << "Stored procedure returned SQLCODE " << sqlca.sqlcode << endl;
  }

  return (0);
} // Spclient::callClobExtract

int Spclient::callDBINFO(char *job)
{
  /********************************************************\
  * Call DBINFO_EXAMPLE stored procedure                   *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    char inDbinfoJob[9];
    double outDbinfoSalary;
    char outDbinfoDbName[129]; // name of database from DBINFO structure
    char outDbinfoDbVersion[9]; // version of database from DBINFO structure
    // declare NULL indicators for each parameter
    sqlint16 inDbinfoJobInd;
    sqlint16 outDbinfoSalaryInd;
    sqlint16 outDbinfoDbNameInd;
    sqlint16 outDbinfoDbVersionInd;
  EXEC SQL END DECLARE SECTION;

  strcpy(inDbinfoJob, job);
  inDbinfoJobInd = 0;

  cout << "\nCALL stored procedure named DBINFO_EXAMPLE " << endl;

  // DBINFO_EXAMPLE is of parameter style SQL, so pass null indicators
  EXEC SQL CALL DBINFO_EXAMPLE(:inDbinfoJob:inDbinfoJobInd, 
                               :outDbinfoSalary:outDbinfoSalaryInd,
                               :outDbinfoDbName:outDbinfoDbNameInd,
                               :outDbinfoDbVersion:outDbinfoDbVersionInd);
  EMB_SQL_CHECK("CALL DBINFO_EXAMPLE");
  
  if (sqlca.sqlcode == 0 && outDbinfoSalaryInd == 0)
  {
    cout << "Stored procedure returned successfully" << endl; 
    cout << "Average salary for job " << inDbinfoJob << " = "
         << setw(9) << outDbinfoSalary << endl;
  }       
  
  if (outDbinfoDbNameInd == 0)
  {
    cout << "Database name from DBINFO structure = " ;
    for (int i = 0; outDbinfoDbName[i] != ' '; i++) 
      cout << outDbinfoDbName[i];
  }
  
  if (outDbinfoDbVersionInd == 0)
  {         
    cout << "\nDatabase version from DBINFO structure = "
         << outDbinfoDbVersion << endl;
  }
  
  return (0);
} // Spclient::callDBINFO

int Spclient::callProgramTypeMain(char *job)
{
  /********************************************************\
  * Call MAIN_EXAMPLE stored procedure                     *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    char inMainJob[9];
    double outMainSalary;
    // declare NULL indicators for each parameter
    sqlint16 inMainJobInd;
    sqlint16 outMainSalaryInd;
  EXEC SQL END DECLARE SECTION;
  
  if (job == NULL)
  {
    inMainJobInd = -1;
  }
  else
  {
    strcpy(inMainJob, job);  
    inMainJobInd = 0;
  }
    
  cout << "\nCALL stored procedure named MAIN_EXAMPLE " << endl;
    
  // MAIN_EXAMPLE is of parameter style SQL, so pass null indicators
  EXEC SQL CALL MAIN_EXAMPLE(:inMainJob:inMainJobInd, 
                             :outMainSalary:outMainSalaryInd);
  EMB_SQL_CHECK("CALL MAIN_EXAMPLE");

  if (sqlca.sqlcode == 0)
  {
    cout << "Stored procedure returned successfully" << endl;
    cout << "Average salary for job " << inMainJob << " = "
         << setw(9) << outMainSalary << endl;
  }
  
  return (0);
} // Spclient::callProgramTypeMain

int Spclient::callAllDataTypes()
{
  /********************************************************\
  * Call ALL_DATA_TYPES stored procedure                   *
  \********************************************************/

  EXEC SQL BEGIN DECLARE SECTION;
    // declare host variables for passing data to ALL_DATA_TYPES
    sqlint16 inoutAllDataTypesSmallInt;
    sqlint32 inoutAllDataTypesInteger;
    sqlint64 inoutAllDataTypesBigInt;
    float inoutAllDataTypesReal;
    double inoutAllDataTypesDouble;
    char outAllDataTypesChar[2];
    char outAllDataTypesChars[16];
    char outAllDataTypesVarchar[13];
    char outAllDataTypesDate[11];
    char outAllDataTypesTime[9];
  EXEC SQL END DECLARE SECTION;

  inoutAllDataTypesSmallInt = 32000;
  inoutAllDataTypesInteger = 2147483000;
  inoutAllDataTypesBigInt = 2147480000;
  // maximum value of BIGINT is 9223372036854775807
  // but some platforms only support 32-bit integers
  inoutAllDataTypesReal = 100000;
  inoutAllDataTypesDouble = 2500000;
  
  cout << "\nCALL stored procedure named ALL_DATA_TYPES " << endl;

  // ALL_DATA_TYPES is of parameter style SQL
  EXEC SQL CALL ALL_DATA_TYPES(:inoutAllDataTypesSmallInt, 
                               :inoutAllDataTypesInteger,
                               :inoutAllDataTypesBigInt, 
                               :inoutAllDataTypesReal, 
                               :inoutAllDataTypesDouble, 
                               :outAllDataTypesChar, 
                               :outAllDataTypesChars, 
                               :outAllDataTypesVarchar,
                               :outAllDataTypesDate, 
                               :outAllDataTypesTime);
  EMB_SQL_CHECK("CALL ALL_DATA_TYPES");

  // check that the stored procedure executed successfully
  if (sqlca.sqlcode == 0)
  {
    cout << "Stored procedure returned successfully" << endl;

    /********************************************************\
    * Display the sum salaries for the affected department   *
    \********************************************************/

    cout << "Value of SMALLINT = " << inoutAllDataTypesSmallInt << endl;
    cout << "Value of INTEGER = " << inoutAllDataTypesInteger << endl;
    cout << "Value of BIGINT = " << (int) inoutAllDataTypesBigInt << endl;
    cout << "Value of REAL = " << inoutAllDataTypesReal << endl;
    cout << "Value of DOUBLE = " << inoutAllDataTypesDouble << endl;
    cout << "Value of CHAR(1) = " << outAllDataTypesChar << endl;
    cout << "Value of CHAR(15) = " << outAllDataTypesChars << endl;
    cout << "Value of VARCHAR(12) = " << outAllDataTypesVarchar << endl;
    cout << "Value of DATE = " << outAllDataTypesDate << endl;
    cout << "Value of TIME = " << outAllDataTypesTime << endl;
  }
  else
  {
    // print the error message
    cout << "Stored procedure returned SQLCODE " << sqlca.sqlcode << endl;
  }
  return (0);
} // Spclient::callAllDataTypes

int main(int argc, char *argv[])
{
  int rc = 0;
  CmdLineArgs check;
  DbEmb db;

  // check the command line arguments
  rc = check.CmdLineArgsCheck1(argc, argv, db);
  if (rc != 0)
  {
    return rc;
  }

  cout << "HOW TO CALL VARIOUS STORED PROCEDURES." << endl; 

  // connect to database
  rc = db.Connect();
  if (rc != 0)
  {
    return rc;
  }

  // set the output mode
  cout.setf(ios::fixed, ios::floatfield);
  cout.precision(2);

  // call the store procedures
  Spclient spcli;
  spcli.Call_StorProcs();

  return (0);
} // main
// end of program: spclient.sqC