/********************************************************************************  
** Source File Name = autoconf.sqc 
**
** Licensed Materials - Property of IBM
**
** (C) COPYRIGHT International Business Machines Corp. 1995, 2000
** 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 the use of the
**          db2AutoConfig() API. The db2AutoConfig() API configures
**          database and database manager configuration parameters.
**          Within the sample program, a database is configured  
**          in two optional scenarios as determined by specifying "1" or 
**          "2" as the multinode command line paramter (any other value
**          will default to  option "1"). In the first case, the sample
**          database is configured and applied automatically by the
**          db2AutoConfig() API. The recommendation/diagnostics are 
**          produced by the db2AutoConfig() API and printed out to
**          standard output. By specifying "2" as the multinode command 
**          line parameter, the db2AutoConfig() API is used to generate 
**          optimized configuration recommendations for a database on two 
**          nodes.  
**          
**   
** 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.
**
**
**   APIs USED :
**      AUTOCONFIG      	db2AutoConfig()
**      AUTOCONFIG FREE MEMORY  db2AutoConfigMemory()
**      UPDATE DB CFG   	sqlfudb()                                    
**      UPDATE DBM CFG  	sqlfusys()                     
**      SET CLIENT      	sqlesetc()
**      SQLCA MESSAGE           sqlaintp()
**
**    STRUCTURES USED :
**       sqle_conn_setting
**       db2AutoConfigInterface
**       db2AutoConfigArray
**       db2AutoConfigOutput
**       db2AutoConfigValues
**       sqlfupd
**       sqlca
**  
**       internal :
**          print_info :      Displays a diagnostics of system
**          print_infodb :    Displays a recommendations for db cfg
**          print_infodbm :   Displays a recommendations for dbm cfg
**          alloc_mem :       Allocates the proper amount of memory for the
**                            GET DATABASE CONFIGURATION API to fill with
**                            data.
**
**       external :
**          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 in to the "autoconf" program.
**
**
**    EXTERNAL DEPENDENCIES :
**       - Ensure existence of database for precompile purposes.
**       - Compile and link with your platform's DB2 supported C compiler.
**      
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sql.h>
#include <sqlutil.h>
#include "db2AuCfg.h"
#include "utilemb.h"


EXEC SQL INCLUDE SQLCA;

EXEC SQL BEGIN DECLARE SECTION;
  char dbName[16];
  char userid[30];
  char passwd[30];
EXEC SQL END DECLARE SECTION;

#define NUMSETTINGS  3 

#define  CHCKERR(s)   if (sqlca.sqlcode  < 0){ print_err(&sqlca); return -1; }



/**************************************************************
  This procedure prints error information released by the APIs.
***************************************************************/
    
void print_err(struct sqlca *ca)
{
   char err[512];
   printf("________________ERROR INFO_________________________\n");
      sqlaintp(err, sizeof(err), 80, ca);
   printf(" err \n");
   printf("SQLCODE   : %d \n",ca->sqlcode);
   printf("SQLERRMC : %s \n",ca->sqlerrmc);
   printf("SQLERRP   : %s \n",ca->sqlerrp);
   printf("_______________END ERROR INFO______________________ \n");
   return;
}


/******************************************************************
  This procedure prints diagnotic information released by the APIs.
*******************************************************************/

int print_info(db2AutoConfigDiags *Diag )
{

   int i =0;

   printf(" Token, Value  \n") ;

   while( i < (Diag->numElements) )
   {
   printf("%d     %d \n",(Diag->pElements[i]).token ,(Diag->pElements[i]).value );
   i++;
   }
   
   return 0;
}


/*****************************************************************
  Procedure to produce db cfg recommendations produced by the API.
******************************************************************/

int print_infodb(struct sqlfupd *itemList, int num)
{
  int i =0;


 printf("Token, Value \n");

  while( i < num )
   {

   int tok = itemList[i].token;
     if( /* these are db cfg tokens */
          tok == SQLF_DBTN_BUFF_PAGE 
       || tok == SQLF_DBTN_CATALOGCACHE_SZ
       || tok == SQLF_DBTN_DFT_DEGREE
       )
      {      
       printf(" %d     %d \n",itemList[i].token,*(int *)itemList[i].ptrvalue );
      }
   i++;
   
   }
   
   return 0;
}



/****************************************************************
procedure to produce dbm cfg recommendations produced by the API.
*****************************************************************/

int print_infodbm(struct sqlfupd *itemList, int num)
{
  int i =0;


 printf( " Token, Value \n");

  while( i < num )
   {

   int tok = itemList[i].token;
     if(  /* these are dbm cfg tokens */
          tok == SQLF_KTN_NUM_POOLAGENTS
       || tok == SQLF_KTN_SHEAPTHRES
      )
      {      
       printf("%d    %d \n",itemList[i].token, *(int *)itemList[i].ptrvalue);
      }

     if(  /* these are dbm cfg tokens */
         tok == SQLF_KTN_ASLHEAPSZ
      )
      {      
       printf(" %d    %d \n",itemList[i].token, *(short *)itemList[i].ptrvalue);
      }


 
   i++;
   
   }
   
   return 0;
}


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


  struct sqle_conn_setting connSetting[NUMSETTINGS];
 
  SQL_API_RC rc;
 
  struct sqlca sqlca;

  db2AutoConfigInterface autoConfigInterface;  

  int inputCount = 2; 
                  
  /* input to API */
  db2int32 mem_percent; /* specify 250 percent of server memory used on dbm*/
  db2int32 workload;     /* specify that our workload is mixed queries and transactions*/

  unsigned short token;
  int i = autoConfigInterface.oResult.oNewDbmValues.numElements - 1; 

 if (  argc != 5)
   {
  printf("autoconf <dbname> <userid> <passwd> <1|2> \n");
   return -1;
   }

   strcpy(dbName, argv[1]);
   strcpy(userid, argv[2]);
   strcpy(passwd, argv[3]);
   

 printf( "________ STARTING AUTOCONF TESTCASE ON INSTANCE OWNING NODE (node 0) \n");


  
/*1 set client */

if (atoi(argv[4]) == 2 ) /* need to connect and attach to node if MPP */
  { 
  /* attach to node 0 */
  connSetting[0].type = SQL_ATTACH_NODE;
  connSetting[0].value = 0;
  
  /* connect to node 0 */
  connSetting[1].type = SQL_CONNECT_NODE;
  connSetting[1].value = 0;


  /* disconnect from node on commit (implicit when connect reset) */
  connSetting[2].type = SQL_DISCONNECT;
  connSetting[2].value = SQL_DISCONNECT_AUTO; 
  
  sqlesetc(&connSetting[0], NUMSETTINGS,&sqlca);
  printf("SQLESETC instance owning node \n");
  CHCKERR("set client");
  }


/*2 connect to database */

  EXEC SQL CONNECT TO :dbName USER :userid USING :passwd;
 printf("______Connect \n");
  CHCKERR("connect db");


  
/*3  ENTER PARMS INTO CONFIG API AND INTERFACE */
  
 
  
  
  /* allocating memory for input parameters */

  autoConfigInterface.iParams.pElements =
    (db2AutoConfigElement *) malloc(sizeof(db2AutoConfigElement)*inputCount);

  /* set up the interface for calling db2AutoConfig */

  autoConfigInterface.iProductID = DB2_SG_PID_DEFAULT;
  strcpy(autoConfigInterface.iDbAlias, dbName);
  strcpy(autoConfigInterface.iProductVersion,"1.1");
  /*** IMPORTANT: the recommendations are automatically 
                applied to db/dbm cfg 
   ***/
  autoConfigInterface.iApply = DB2_SG_APPLY;

  mem_percent = 25;
  workload    =  2;

  autoConfigInterface.iParams.numElements = 2;
  autoConfigInterface.iParams.pElements[0].token = DB2_SG_MEMORY_PERCENTAGE;   
  autoConfigInterface.iParams.pElements[0].value = mem_percent;
  autoConfigInterface.iParams.pElements[1].token = DB2_SG_WORKLOAD;
  autoConfigInterface.iParams.pElements[1].value = workload;

  

/*4 AUTOCONFIG CALL */

  rc = db2AutoConfig(db2Version710, &autoConfigInterface, &sqlca);
  printf("______DB2AUTOCONFIG_________ \n");
  CHCKERR("db2autoconfig"); 



/*5 PRINT RECOMMENDATION AND DIAGNOSTICS */
  if (rc == DB2_SG_RC_OK) 
  {
   printf("NUMBER OF DIAGNOSTICS: %d \n",autoConfigInterface.oResult.oDiagnostics.numElements);
 

   
    if (autoConfigInterface.oResult.oDiagnostics.numElements > 0) 
    {
    	/* handle the diagnostic results */

      	printf("==>resource values are not optimizable, diagnostics produced: \n");

        print_info(&((autoConfigInterface.oResult).oDiagnostics)
                   );

       printf(" __________________ \n");

    }  

    if ( autoConfigInterface.oResult.oOldDbValues.numElements >0 )
    {
    	/* handle the configuration results */

     	printf("==> resource values are optimizable  recommendations produced: \n" ); 
   
       printf("==>  NUMBER OF PRODUCED OLD DB CFG RECOMMENDATIONS: \n", autoConfigInterface.oResult.oOldDbValues.numElements );
       printf("==> PRODUCED VALUES  \n" ); 
        print_infodb(
	autoConfigInterface.oResult.oOldDbValues.pConfigs,
        autoConfigInterface.oResult.oOldDbValues.numElements
                  );
       printf(" __________________ \n");


    }


    if ( autoConfigInterface.oResult.oNewDbValues.numElements >0 )
    {

       printf("==>  NUMBER OF PRODUCED NEW DB CFG RECOMMENDATIONS:%d \n",autoConfigInterface.oResult.oNewDbValues.numElements);
       printf("==> PRODUCED VALUES \n"); 
        print_infodb(
	autoConfigInterface.oResult.oNewDbValues.pConfigs,
        autoConfigInterface.oResult.oNewDbValues.numElements
        	          );


       printf(" __________________ \n" );

    }



    if ( autoConfigInterface.oResult.oOldDbmValues.numElements >0 )
    {
       printf("==>  NUMBER OF PRODUCED OLD DBM CFG RECOMMENDATIONS: %d \n",
       autoConfigInterface.oResult.oOldDbmValues.numElements);
       printf("==> PRODUCED VALUES  \n"); 
        print_infodbm(
	autoConfigInterface.oResult.oOldDbmValues.pConfigs,
        autoConfigInterface.oResult.oOldDbmValues.numElements
                  );
 
       printf(" __________________ \n");
    }


    if ( autoConfigInterface.oResult.oNewDbmValues.numElements >0 )
    {

       printf("==> NUMBER OF PRODUCED NEW DBM CFG RECOMMENDATIONS: %d \n",autoConfigInterface.oResult.oNewDbmValues.numElements);
       printf("==> PRODUCED VALUES \n" ); 
        print_infodbm(
	autoConfigInterface.oResult.oNewDbmValues.pConfigs,
        autoConfigInterface.oResult.oNewDbmValues.numElements      
	         );

       printf(" __________________ \n");
     
     } 

  


/*6 FREE MEMORY */
        
    /* must free all the memory allocated by db2AutoConfig() */
    db2AutoConfigFreeMemory(db2Version710,&autoConfigInterface,&sqlca);


  }

  else 
  {
   /* handle error */
   printf("ERROR in API CALL \n");
  }


  /* DISCONNECT FROM NODE */
  EXEC SQL CONNECT RESET; 
 printf("______+CONNECT RESET \n");
  CHCKERR("connect reset");   




 /* IF 5 ARGUMENTS SPECIFIED, TREAT AS PARTIONED DATABASE WITH A SECOND NODE */
if (atoi(argv[4]) == 2)
 {
 /*********************************/
 /*********************************/
 /* REPEAT FOR SECOND NODE (Node 1) */




 printf( "________ OPTION 2 CONFIGURING DATABASE PORTION RESIDING ON NON INSTANCE OWNING NODE (node 1) \n");


  
/*1 set client */
  /* ATTACH TO NODE 1 */
  connSetting[0].type = SQL_ATTACH_NODE;
  connSetting[0].value = 1;

  /* CONNECT TO NODE 1 */
  connSetting[1].type = SQL_CONNECT_NODE;
  connSetting[1].value = 1;

  /* DISCONNECT TO NODE ON COMMIT */ 
  connSetting[2].type = SQL_DISCONNECT;
  connSetting[2].value = SQL_DISCONNECT_AUTO; 


  sqlesetc(&connSetting[0], NUMSETTINGS,&sqlca);
 printf("______+SQLESETC 2nd node (NODE 1) \n" );
  CHCKERR("set client");


/*2 connect to database */

  EXEC SQL CONNECT TO :dbName USER :userid USING :passwd;
  printf("____________++connect to db \n"); 
  CHCKERR("connect to db");


/*3  ENTER PARMS INTO API AND INTERFACE */

                  
/* input to smartguide */
   mem_percent = 45; /* percentage of memory for dbm server is 34% */
   workload = 2; /* workload is mixed with queries and transactions */
   inputCount = 2;
  
  /* allocating memory for input parameters */

  autoConfigInterface.iParams.pElements =
    (db2AutoConfigElement *) malloc(sizeof(db2AutoConfigElement) *
     inputCount);

  /* set up the interface for calling db2AutoConfig */

  autoConfigInterface.iProductID = DB2_SG_PID_DEFAULT;
  strcpy(autoConfigInterface.iDbAlias, dbName);
  strcpy(autoConfigInterface.iProductVersion,"1.1");
  
 /*** IMPORTANT - this time the configuration parameters
  ***             are not automatically applied
  ***/  
  autoConfigInterface.iApply = DB2_SG_APPLY;

  autoConfigInterface.iParams.numElements = 2;
  autoConfigInterface.iParams.pElements[0].token = DB2_SG_MEMORY_PERCENTAGE;   
  autoConfigInterface.iParams.pElements[0].value = mem_percent;
  autoConfigInterface.iParams.pElements[1].token = DB2_SG_WORKLOAD;
  autoConfigInterface.iParams.pElements[1].value = workload;
 
/*4 AUTOCONFIG CALL */

  rc = db2AutoConfig(db2Version710, &autoConfigInterface, &sqlca);
  printf("______+DB2AUTOCONFIG_________ \n");
  CHCKERR("db2 connect to sample"); 



/*6 PRINT RECOMMENDATION AND DIAGNOSTITCS */
  if (rc == DB2_SG_RC_OK) 
  {
   printf("NUMBER OF DIAGNOSTICS: %d \n",autoConfigInterface.oResult.oDiagnostics.numElements);
       

   
    if (autoConfigInterface.oResult.oDiagnostics.numElements > 0) 
    {
    	/* handle the diagnostic results */

      	printf("==>resource values are not optimizable,diagnostics produced: ");

        print_info(&((autoConfigInterface.oResult).oDiagnostics));

       printf(" ____________________ \n");

    }  

    if ( autoConfigInterface.oResult.oOldDbValues.numElements >0 )
    {
    	/* handle the configuration results */

     	printf("==> resource values are optimizable recommendations produced: \n" ); 
   
        printf("==>  NUMBER OF PRODUCED OLD DB CFG RECOMMENDATIONS: %d \n", 
        autoConfigInterface.oResult.oOldDbValues.numElements );
        printf("==> PRODUCED VALUES  \n" ); 
        print_infodb(
	autoConfigInterface.oResult.oOldDbValues.pConfigs,
        autoConfigInterface.oResult.oOldDbValues.numElements
                  );
       printf(" ____________________ \n");


    }


    if ( autoConfigInterface.oResult.oNewDbValues.numElements >0 )
    {
       printf("==>  NUMBER OF PRODUCED NEW DB CFG RECOMMENDATIONS: %d \n", 
       autoConfigInterface.oResult.oNewDbValues.numElements);
       printf("==> PRODUCED VALUES  \n" ); 
        print_infodb(
	autoConfigInterface.oResult.oNewDbValues.pConfigs,
        autoConfigInterface.oResult.oNewDbValues.numElements
        	          );


       printf(" ____________________ \n" );

    }



    if ( autoConfigInterface.oResult.oOldDbmValues.numElements >0 )
    {
        printf("==>  NUMBER OF PRODUCED OLD DBM CFG RECOMMENDATIONS: %d \n", 
        autoConfigInterface.oResult.oOldDbmValues.numElements);       
        printf("==> PRODUCED VALUES  \n"); 
        print_infodbm(
	autoConfigInterface.oResult.oOldDbmValues.pConfigs,
        autoConfigInterface.oResult.oOldDbmValues.numElements
                  );
 
       printf(" __________________** \n");
    }


    if ( autoConfigInterface.oResult.oNewDbmValues.numElements >0 )
    {

        printf("==>  NUMBER OF PRODUCED NEW DBM CFG RECOMMENDATIONS: %d \n", 
               autoConfigInterface.oResult.oNewDbmValues.numElements);
        printf("==> PRODUCED VALUES  \n" ); 
        print_infodbm(
	autoConfigInterface.oResult.oNewDbmValues.pConfigs,
        autoConfigInterface.oResult.oNewDbmValues.numElements      
	         );

       printf("__________________** \n");
     
     } 


/*6 FREE MEMORY */
        
    /* must free all the memory allocated by db2AutoConfig() */
    db2AutoConfigFreeMemory(db2Version710,&autoConfigInterface,&sqlca);


  }

  else 
  {
    /* handle error */
    printf(" ERROR in API CALL \n");
  }



  EXEC SQL CONNECT RESET; 
  printf("_____CONNECT RESET \n");
  CHCKERR("connect reset");


 }

  return 0;
}