//
//  Source File Name = outcli.sqC   
//  
//  Licensed Materials - Property of IBM 
//  
//  (C) COPYRIGHT International Business Machines Corp. 1995, 1997 
//  All Rights Reserved. 
//  
//  US Government Users Restricted Rights - Use, duplication or 
//  disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
//  
//  
//  PURPOSE: This sample program demonstrates stored procedures in C++. 
//  
//           There are two parts to this program: 
//              1. the outcli executable (placed on the client) 
//              2. the outsrv library (placed on the server) 
//  
//           There are two different ways to invoke from outcli: 
//              1. EXEC SQL CALL :procname (:sal:salind) 
//              2. EXEC SQL CALL :procname USING DESCRIPTOR :*inout_sqlda 
//  
//           When the CALL USING and sqleproc API are used, 
//           the outcli routine will allocate and initialize a one 
//           variable SQLDA to point to the data. 
//           This SQLDA may be used for both input and output, 
//           although in this program it is used for output only. 
//  
//           When the CALL with Host Variable is used, 
//           the precompiler allocates and initialize an internal one 
//           variable SQLDA, again for both input and output purpose. 
//  
//           Any of the above 2 ways will call the outsrv routine stored 
//           in the outsrv library. 
//  
//           The outsrv routine will obtain the median salary of 
//           employees in the "staff" table of the "sample" database. 
//           This value will be placed in the output SQLDA and 
//           returned to the outcli routine.  The outcli routine will 
//           then print out the median salary. 
//  
//  NOTE:    All variables on the EXEC SQL CALL statements are assummed to 
//           be used for both input and output.  One technique to minimize 
//           network flow is for the client program to provide indicator 
//           variables with all its host variables. 
//             -  The client program should set the "output-only" variable's 
//                indicator value to -1 before issuing the CALL. 
//             -  The server program should set the "input-only" variable's 
//                indicator value to -128 before returning. 
//  
//           This will cause the transmission of just the indicator value 
//           instead of the host variable itself.  This will be worthwhile 
//           when dealing with fairly long character data. 
//  
//  An external function "check_error" is contained in the file "util.C" 
//  which must be compiled along with this file. 
//  
//     EXTERNAL DEPENDENCIES : 
//        - Existing database for precompile purposes. 
//        - Precompile with the SQL precompiler (PREP in DB2) 
//        - Binding to a database (BIND in DB2) 
//        - Compiling and linking with the IBM Cset++ compiler (AIX and OS/2) 
//          or the Microsoft Visual C++ compiler (Windows) 
//          or the compiler supported on your platform. 
//  
//  For more information about these samples see the README file. 
//  
//  For more information on programming in C++, see the 
//     -  "Programming in C and C++" section of the Application Development Guide 
//  
//  For more information on building C++ applications, see the: 
//     - "Building C++ Applications" section of the Application Building Guide. 
//  
//  For more information on the SQL language see the SQL Reference. 
//  

#include <iostream.h>
#include <stdlib.h>
#include <sql.h> /* :rk.1:erk. */
#include <sqlda.h>
#include <sqlca.h>
#include <string.h>
#include "util.h"

EXEC SQL INCLUDE SQLCA;

#define  CHECKERR(CE_STR)   if (check_error (CE_STR, &sqlca) != 0)


class Outsrv {
   public:
      Outsrv();
      Outsrv(char *, char *, char *);
      InitHV();
      CallSQLDA();
      CallHV();
      ~Outsrv();

   private:
      EXEC SQL BEGIN DECLARE SECTION;
         char database[9];
         char userid[9];
         char passwd[19];

         /* Declare a Local Variable for Holding the Procedure's Name */
         char procname[255];

         /* Declare Local Variables for Holding Returned Data */
         double sal;
         short  salind;
      EXEC SQL END DECLARE SECTION;

      struct sqlda *inout_sqlda;
};


Outsrv::Outsrv () {
   cout << "Connect to default database with default userid and password\n";
   EXEC SQL CONNECT TO sample;
   CHECKERR ("CONNECT TO") exit(1);
}


Outsrv::Outsrv (char *database, char *userid, char *passwd) {
   cout << "Connecting to database " << database << '\n';
   EXEC SQL CONNECT TO :database USER :userid USING :passwd;
   CHECKERR ("CONNECT TO :database") exit(1);
}


Outsrv::InitHV () {
   strcpy (procname, "outsrv");
   sal = 0.0;
   salind = 0;
   return 0;
}


Outsrv::CallSQLDA () {
   // -----------------------------------------------// 
   //  Call the Remote Procedure via CALL with SQLDA // 
   // -----------------------------------------------// 
   inout_sqlda = (struct sqlda *) malloc (SQLDASIZE(1));

   //  Initialize the output SQLDA 
   inout_sqlda->sqln = 1;
   inout_sqlda->sqld = 1;
   inout_sqlda->sqlvar[0].sqltype = SQL_TYP_NFLOAT;
   inout_sqlda->sqlvar[0].sqllen  = sizeof( double );
   inout_sqlda->sqlvar[0].sqldata = (char *)&sal;
   inout_sqlda->sqlvar[0].sqlind  = (short *)&salind;

   cout << "Use CALL with SQLDA to invoke the Server Procedure name outsrv\n";
   salind = -1;                  //  Sal has no input, so set to null 
   EXEC SQL CALL :procname USING DESCRIPTOR :*inout_sqlda;
   CHECKERR ("CALL WITH SQLDA") return 1;
   cout << "Server Procedure Complete.\n";

   //  Print Salary Returned in The Host Variables 
   cout << "Median Salary = " << sal << "\n\n";

   //  Free allocated memory 
   free( inout_sqlda );
   return 0;
}


Outsrv::CallHV () {
   // --------------------------------------------------------// 
   //  Call the Remote Procedure via CALL with Host Variables // 
   // --------------------------------------------------------// 
   cout << "Use CALL with Host Variable to invoke the Server Procedure "
      "named outsrv\n";
   salind = -1;                  //  Sal has no input, so set to null  
   EXEC SQL CALL :procname (:sal :salind);  /* :rk.6a:erk. */
   CHECKERR ("CALL WITH HOST VARIABLES") return 1;
   cout << "Server Procedure Complete.\n";

   //  Print Salary Returned in The Host Variables 
   cout << "Median Salary = " << sal << "\n\n";
   return 0;
}


Outsrv::~Outsrv () {
   //  Disconnect from Remote Database 
   EXEC SQL CONNECT RESET;
   CHECKERR ("CONNECT RESET") exit(1);
}


int main(int argc, char *argv[]) {


   if (argc == 4) {
      Outsrv outsrvSample (argv[1], argv[2], argv[3]);

      outsrvSample.InitHV();
      outsrvSample.CallHV();
      outsrvSample.CallSQLDA();
   } else if (argc == 1) {
      Outsrv outsrvSample;

      outsrvSample.InitHV();
      outsrvSample.CallHV();
      outsrvSample.CallSQLDA();
   } else {
      cout << "\nUSAGE: outcli remote_database userid passwd\n\n";
   } //  end if 

   return 0;

}
//  end of program : outcli.sqC