//
//  Source File Name = inpcli.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: 
//               - the inpcli executable (placed on the client) 
//               - the inpsrv library (placed on the server) 
//  
//           The inpcli routine will invoke the inpsrv routine 
//           with the name of a table and the names of three 
//           presidents of the United States. 
//           The inpsrv routine will take the information received 
//           and create a table called "presidents" in the sample 
//           database.  It will then insert the values it received in 
//           this table. 
//  
//           There are two different ways to invoke from inpcli: 
//              1. EXEC SQL CALL :procname (:*table_name, 
//                                          :*data_item0, 
//                                          :*data_item1, 
//                                          :*data_item2); 
//              2. EXEC SQL CALL :procname USING DESCRIPTOR :inout_sqlda 
//  
//           When the CALL USING is used, 
//           the inpcli routine will allocate and initialize a four 
//           variables SQLDA to point to the data. 
//           This SQLDA may be used for both input and output, 
//           although in this program it is used for input 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 produce the same result. 
//  
//  NOTE 1:  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. 
//  
//  
//     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 <string.h>
#include <sqlenv.h>
#include <sqlda.h>
#include <sqlutil.h>
#include "util.h"

EXEC SQL INCLUDE SQLCA;

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

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

   private:
      EXEC SQL BEGIN DECLARE SECTION;
         char database[9];
         char userid[9];
         char passwd[19];
         char procname[255];
         char table_name[11];
         char data_item0[21];
         char data_item1[21];
         char data_item2[21];
         short tableind, dataind0, dataind1, dataind2;
      EXEC SQL END DECLARE SECTION;

      /* Declare Variables for CALL USING */
      struct sqlda   *inout_sqlda;
};


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

Inpsrv::Inpsrv (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);
}

Inpsrv::InitHV() {
   strcpy(procname, "inpsrv");
   strcpy(table_name, "PRESIDENTS");
   strcpy(data_item0, "Washington");
   strcpy(data_item1, "Jefferson");
   strcpy(data_item2, "Lincoln");
   return 0;
}

Inpsrv::CallSQLDA () {
   //  Allocate and Initialize Input SQLDA.   /* :rk.1:erk. */ 
   inout_sqlda = (struct sqlda *)malloc( SQLDASIZE(4) );
   inout_sqlda->sqln = 4;
   inout_sqlda->sqld = 4;

   inout_sqlda->sqlvar[0].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[0].sqldata = table_name;
   inout_sqlda->sqlvar[0].sqllen  = strlen( table_name ) + 1;
   inout_sqlda->sqlvar[0].sqlind  = &tableind;

   inout_sqlda->sqlvar[1].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[1].sqldata = data_item0;
   inout_sqlda->sqlvar[1].sqllen  = strlen( data_item0 ) + 1;
   inout_sqlda->sqlvar[1].sqlind  = &dataind0;

   inout_sqlda->sqlvar[2].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[2].sqldata = data_item1;
   inout_sqlda->sqlvar[2].sqllen  = strlen( data_item1 ) + 1;
   inout_sqlda->sqlvar[2].sqlind  = &dataind0;

   inout_sqlda->sqlvar[3].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[3].sqldata = data_item2;
   inout_sqlda->sqlvar[3].sqllen  = strlen( data_item2 ) + 1;
   inout_sqlda->sqlvar[3].sqlind  = &dataind0;

   // -----------------------------------------------// 
   //  Call the Remote Procedure via CALL with SQLDA // 
   // -----------------------------------------------// 
   cout << "Use CALL with SQLDA to invoke the Server Procedure named inpsrv\n";

   //  Set the indicatore variables. 
   tableind = dataind0 = dataind1 = dataind2 = 0;

   EXEC SQL CALL :procname USING DESCRIPTOR :*inout_sqlda;  /* :rk.2b:erk. */
   CHECKERR ("CALL WITH SQLDA") return 1;
   cout << "Server Procedure Complete.\n\n";

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


Inpsrv::CallHV() {
   // --------------------------------------------------------// 
   //  Call the Remote Procedure via CALL with Host Variables // 
   // --------------------------------------------------------// 
   cout << "Use CALL with Host Variables to invoke the Server Procedure "
      << "named inpsrv.\n";

   //  Set the indicator variables. 
   tableind = dataind0 = dataind1 = dataind2 = 0;

   EXEC SQL CALL :procname (:table_name:tableind, :data_item0:dataind0,
      :data_item1:dataind1, :data_item2:dataind2); /* :rk.2a:erk. */
   CHECKERR ("CALL WITH HOST VARIABLE") return 1;
   cout << "Server Procedure Complete.\n\n";

   return 0;
}


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


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

   if (argc == 4) {
      Inpsrv inpsrvSample (argv[1], argv[2], argv[3]);

      inpsrvSample.InitHV();
      inpsrvSample.CallHV();
      inpsrvSample.CallSQLDA();
   } else if (argc == 1) {
      Inpsrv inpsrvSample;

      inpsrvSample.InitHV();
      inpsrvSample.CallHV();
      inpsrvSample.CallSQLDA();

   } else {
      cout << "\nUSAGE: inpcli remote_database userid passwd\n\n";
   } //  end if 

   return 0;
}
//  end of program : inpcli.sqC