/******************************************************************************
**
** Source File Name = utilcli.c   
**
** 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 :
**    - contains various functions, used by most other samples:
**
**       1. HANDLE_CHECK section 
**
**          1.1 - HandleInfoPrint - prints on the screen everything that
**                                  goes unexpected with a SQL... function.
**                  1.1.1 - HandleLocationPrint    - used by HandleInfoPrint
**                  1.1.2 - HandleDiagnosticsPrint - used by HandleInfoPrint
**          1.2 - CLIAppCleanUp - rolls back all the transactions
**                              - closes all the connections
**                              - frees all the connection handles
**                              - frees the environment handle
**          1.3 - StmtResourcesFree - no more comments
**
**       2. non HANDLE_CHECK section
**
**          2.1 - CmdLineArgsCheck1 - checks the command line arguments, ver.1
**          2.2 - CmdLineArgsCheck2 - checks the command line arguments, ver.2
**          2.3 - CLIAppInit - allocates an environment handle
**                           - alloctes a connection handle
**                           - set AUTOCOMMIT off or on
**                           - connects to the database
**          2.4 - CLIAppTerm - disconnects from the database
**                           - frees the connection handle
**                           - frees the environment handle
**          2.5 - StmtResultPrint - no more comments
**
** 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.
**
** For more information on the SQL language see the SQL Reference.
**
******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlcli1.h>
#include <sqlutil.h>
#include <sqlenv.h>
#include "utilcli.h"

/* local functions for util.c */
void HandleLocationPrint( SQLRETURN, int, char * );
void HandleDiagnosticsPrint( SQLSMALLINT, SQLHANDLE );

/*#############################################################################
**    1. HANDLE_CHECK section
**
**        1.1 - HandleInfoPrint - prints on the screen everything that
**                                goes unexpected with a SQL... function.
**                1.1.1 - HandleLocationPrint    - used by HandleInfoPrint
**                1.1.2 - HandleDiagnosticsPrint - used by HandleInfoPrint
**        1.2 - CLIAppCleanUp - rolls back all the transactions
**                            - closes all the connections
**                            - frees all the connection handles
**                            - frees the environment handle
**        1.3 - StmtResourcesFree - no more comments
**        1.4 - EnvHandleFree - frees the environment handle
#############################################################################*/

/******************************************************************************
**        1.1 - HandleInfoPrint - prints on the screen everything that
**                                goes unexpected with a SQL... function.
******************************************************************************/
int HandleInfoPrint( SQLSMALLINT htype,  /* handle type identifier */
                     SQLHANDLE   hndl,   /* handle used by the SQL...func. */
                     SQLRETURN   sqlrc,  /* ret. code of the SQL... func. */
                     int         line,      
                     char *      file )
{   int rc = 0;

    switch ( sqlrc )
    {   case SQL_SUCCESS:
            rc = 0;
            break ;
        case SQL_INVALID_HANDLE:
            printf( "\n-SQL INVALID HANDLE-----\n");	    
            HandleLocationPrint( sqlrc, line, file);
            rc = 1;    
            break ;    
        case SQL_ERROR:
            printf( "\n--SQL ERROR--------------\n");	    
            HandleLocationPrint( sqlrc, line, file);
            HandleDiagnosticsPrint( htype, hndl);
            rc = 2;
            break ;
        case SQL_SUCCESS_WITH_INFO:
            rc = 0;
            break ;
        case SQL_STILL_EXECUTING :
            rc = 0;
            break ;
        case SQL_NEED_DATA :
            rc = 0;
            break ;	    
        case SQL_NO_DATA_FOUND:
            rc = 0;
            break ;
        default:
            printf( "\n--default----------------\n");
            HandleLocationPrint( sqlrc, line, file);
            rc = 3;
            break ;
    }

    return ( rc ) ;
}

/*--> SQLL1X32.SCRIPT */
/******************************************************************************
**                1.1.1 - HandleLocationPrint    - used by HandleInfoPrint
******************************************************************************/
void HandleLocationPrint( SQLRETURN   sqlrc,   
                          int         line, 
                          char *      file  
                        )
{   printf( "  sqlrc             = %d\n", sqlrc);
    printf( "  line              = %d\n", line);
    printf( "  file              = %s\n", file);
}

/******************************************************************************
**                1.1.2 - HandleDiagnosticsPrint - used by HandleInfoPrint
******************************************************************************/
void HandleDiagnosticsPrint( SQLSMALLINT htype, /* handle type identifier */
                             SQLHANDLE   hndl  /* handle */
                           )
{   SQLCHAR     message[SQL_MAX_MESSAGE_LENGTH + 1] ;
    SQLCHAR     SQLSTATE[SQL_SQLSTATE_SIZE + 1] ;
    SQLINTEGER  sqlcode ;
    SQLSMALLINT length, i ;

    i = 1 ;
    /*--> 00003364.snippet */
    while ( SQLGetDiagRec( htype,
                           hndl,
                           i,
                           SQLSTATE,
                           &sqlcode,
                           message,
                           SQL_MAX_MESSAGE_LENGTH + 1,
                           &length
                         ) == SQL_SUCCESS ) {
       printf( "\n  SQLSTATE          = %s\n", SQLSTATE ) ;
       printf( "  Native Error Code = %ld\n", sqlcode ) ;
       printf( "%s\n", message ) ;
       i++ ;
    }
    /* 00003364.snippet <--*/

    printf( "-------------------------\n" ) ;
}


/******************************************************************************
**        1.2 - CLIAppCleanUp - rolls back all the transactions
**                            - closes all the connections
**                            - frees all the connection handles
**                            - frees the environment handle
******************************************************************************/
/* this function is used in HANDLE_CHECK, */
/* it can not use HANDLE_CHECK            */
void CLIAppCleanUp( SQLHANDLE * pHenv,
                    SQLHANDLE a_hdbc[],
                    int a_hdbc_dim)
{   SQLRETURN  sqlrc = SQL_SUCCESS;
    int        rc = 0;
    SQLCHAR    db[SQL_MAX_DSN_LENGTH + 1] ;
    int        db_nb = 0;   

    
    /* rollback all the transactions */
    for( db_nb = 0; db_nb < a_hdbc_dim; db_nb++)
    {   /*--> 00003360.snippet */
        printf( "\nRolling back the transaction nb. %d ...\n", db_nb + 1) ;
        
        sqlrc = SQLEndTran( SQL_HANDLE_DBC, a_hdbc[db_nb], SQL_ROLLBACK ); 
        rc    = HandleInfoPrint( SQL_HANDLE_DBC, a_hdbc[db_nb],
                                 sqlrc, __LINE__, __FILE__);
        if( rc == 0)
        {   printf( "The transaction nb. %d rolled back.\n", db_nb + 1 ) ;
        }
        /* 00003360.snippet <--*/ 
    }
    
    
    /* disconnect from all the databases */
    for( db_nb = 0; db_nb < a_hdbc_dim; db_nb++)
    {   /*--> 00003334.snippet */
        printf( "\nDisconnecting from the database nb. %d ...\n", db_nb + 1) ;
        
        sqlrc = SQLDisconnect( a_hdbc[db_nb] ) ;
        rc    = HandleInfoPrint( SQL_HANDLE_DBC, a_hdbc[db_nb],
                                 sqlrc, __LINE__, __FILE__);
        if( rc == 0)
        {   printf( "Disconnected from the database nb. %d.\n", db_nb + 1 ) ;
        }
        /* 00003334.snippet <--*/ 
    }
        

    /* free all the connection handles */
    for( db_nb = 0; db_nb < a_hdbc_dim; db_nb++)
    {   printf( "\nFreeing the connection handle nb. %d ...\n", db_nb + 1) ;
        sqlrc = SQLFreeHandle( SQL_HANDLE_DBC, a_hdbc[db_nb] ) ;
        rc    = HandleInfoPrint( SQL_HANDLE_DBC, a_hdbc[db_nb],
                                 sqlrc, __LINE__, __FILE__);
        if( rc == 0)
        {   printf( "The connection handle nb. %d is free.\n", db_nb + 1 ) ;
        }		
    }	     

    /*--> 00003338.snippet */
    /* free the environment handle */
    printf("\nFreeing the environment handle ...\n");
    sqlrc = SQLFreeHandle( SQL_HANDLE_ENV,  *pHenv ) ;
    rc    = HandleInfoPrint( SQL_HANDLE_ENV, *pHenv,
                             sqlrc, __LINE__, __FILE__);
    if( rc == 0)
    {   printf("The environment handle is free.\n");
    }
    /* 00003338.snippet <--*/
}
    

/******************************************************************************
**        1.3 - StmtResourcesFree - no more comments	
******************************************************************************/
/* this function is used in STMT_HANDLE_CHECK, */
/* it can not contain STMT_HANDLE_CHECK        */
int  StmtResourcesFree( SQLHANDLE hstmt )
{   SQLRETURN   sqlrc = SQL_SUCCESS;
    int         rc = 0;	

    /*--> 00003339.snippet */
    sqlrc = SQLFreeStmt( hstmt, SQL_UNBIND ) ;
    rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt,
                          sqlrc, __LINE__, __FILE__);
    if( rc != 0) return(1) ;    
    /* 00003339.snippet <--*/ 

    sqlrc = SQLFreeStmt( hstmt, SQL_RESET_PARAMS ) ;
    rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt,
                          sqlrc, __LINE__, __FILE__);
    if( rc != 0) return(1) ;        

    /*--> 00003339.snippet */
    sqlrc = SQLFreeStmt( hstmt, SQL_CLOSE ) ;
    rc = HandleInfoPrint( SQL_HANDLE_STMT, hstmt,
                          sqlrc, __LINE__, __FILE__);
    if( rc != 0) return(1) ;
    /* 00003339.snippet <--*/

    return( 0 );
}
   

/*#############################################################################
**     2. non HANDLE_CHECK section
**
**          2.1 - CmdLineArgsCheck1 - checks the command line arguments, ver.1
**          2.2 - CmdLineArgsCheck2 - checks the command line arguments, ver.2
**          2.3 - CLIAppInit - allocates an environment handle
**                           - alloctes a connection handle
**                           - set AUTOCOMMIT off or on
**                           - connects to the database
**          2.4 - CLIAppTerm - disconnects from the database
**                           - frees the connection handle
**                           - frees the environment handle
**          2.5 - StmtResultPrint - no more comments
#############################################################################*/

/******************************************************************************
**          2.1 - CmdLineArgsCheck1 - checks the command line arguments, ver.1
******************************************************************************/
int  CmdLineArgsCheck1( int argc,
                        char * argv[],
                        char dbAlias[],
                        char user[],
                        char pswd[] )
{   int rc = 0;

    switch (argc)
    {    case 1:
             strcpy(dbAlias, "sample");
             strcpy(user, "");
             strcpy(pswd, "");
             break;
         case 2:
             strcpy(dbAlias, argv[1]);
             strcpy(user, "");
             strcpy(pswd, "");
             break;
         case 4:
             strcpy(dbAlias, argv[1]);
             strcpy(user, argv[2]);
             strcpy(pswd, argv[3]);
             break;    
         default:
             printf( "\nUSAGE: %s [dbAlias [userid  passwd]]]\n", argv[0] ) ;
             rc = 1;
             break;
    }  /* endswitch */

    return (rc);
}

/******************************************************************************
**          2.2 - CmdLineArgsCheck2 - checks the command line arguments, ver.2
******************************************************************************/
int  CmdLineArgsCheck2( int argc,
                        char * argv[],
                        char dbAlias[],
                        char user[],
                        char pswd[],
                        char remoteNodeName[] )
{   int rc = 0;

    switch (argc)
    {    case 1:
             strcpy(dbAlias, "sample");
             strcpy(user, "");
             strcpy(pswd, "");
             strcpy(remoteNodeName, "");   
             break;
         case 2:
             strcpy(dbAlias, argv[1]);
             strcpy(user, "");
             strcpy(pswd, "");
             strcpy(remoteNodeName, "");   	     
             break;
         case 4:
             strcpy(dbAlias, argv[1]);
             strcpy(user, argv[2]);
             strcpy(pswd, argv[3]);
             strcpy(remoteNodeName, "");   	     
             break;   
         case 5:
             strcpy(dbAlias, argv[1]);
             strcpy(user, argv[2]);
             strcpy(pswd, argv[3]);
             strcpy(remoteNodeName, argv[4]);   	     
             break;   	     
         default:
             printf( "\nUSAGE: %s [dbAlias [userid passwd [remoteNodeName]]]\n",
                     argv[0] ) ;
             rc = 1;
             break;
    }  /* endswitch */

    return (rc);
}

/******************************************************************************
**          2.3 - CLIAppInit - allocates an environment handle
**                           - alloctes a connection handle
**                           - set AUTOCOMMIT off or on
**                           - connects to the database
******************************************************************************/
int CLIAppInit( char dbAlias[],
                char user[],
                char pswd[],		
                SQLHANDLE * pHenv,
                SQLHANDLE * pHdbc,
                SQLPOINTER autocommitValue )
{   SQLRETURN  sqlrc = SQL_SUCCESS;
    int        rc = 0;

    /*--> 00003328.snippet */
    /* allocate an environment handle */
    sqlrc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, pHenv ) ;
    if ( sqlrc != SQL_SUCCESS ) 
    {   printf( "\n--ERROR while allocating the environment handle.\n" ) ;
        printf( "  sqlrc             = %d\n", sqlrc);
        printf( "  line              = %d\n", __LINE__);
        printf( "  file              = %s\n", __FILE__);	    
        return( 1 ) ;
    }
    /* 00003328.snippet <--*/

    /*--> 00003328.snippet */
    /* allocate a database connection handle */
    sqlrc = SQLAllocHandle( SQL_HANDLE_DBC, *pHenv, pHdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_ENV, *pHenv, sqlrc, pHenv, pHdbc ) ;
    /* 00003328.snippet <--*/

    /*--> 00003344.snippet */
    /* set AUTOCOMMIT off or on */
    sqlrc = SQLSetConnectAttr( *pHdbc,
                               SQL_ATTR_AUTOCOMMIT,
                               autocommitValue, SQL_NTS) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, *pHdbc, sqlrc, pHenv, pHdbc ) ; 
    /* 00000563.snippet <--*/  

    /*-->00003344.snippet */
    /* connect to the database */
    printf( "\nConnecting to %s ...\n", dbAlias ) ;    
    sqlrc = SQLConnect( *pHdbc,
                     (SQLCHAR *)dbAlias,   SQL_NTS,
                     (SQLCHAR *)user, SQL_NTS,
                     (SQLCHAR *)pswd, SQL_NTS
                   ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, *pHdbc, sqlrc, pHenv, pHdbc ) ;     
    printf( "Connected to %s.\n", dbAlias ) ;
    /* 00000576.snippet <--*/
 
    return( 0 ) ;
}
   /* 00000576.snippet <--*/

/******************************************************************************
**        2.4 - CLIAppTerm - disconnects from the database
**                         - frees the connection handle
**                         - frees the environment handle
******************************************************************************/
int CLIAppTerm( SQLHANDLE * pHenv,
                SQLHANDLE * pHdbc,
                char dbAlias[] )
{   SQLRETURN  sqlrc = SQL_SUCCESS;
    int        rc = 0;
    
    printf( "\nDisconnecting from %s ...\n", dbAlias ) ;
    sqlrc = SQLDisconnect( *pHdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, *pHdbc, sqlrc, pHenv, pHdbc ) ;
    printf( "Disconnected from %s.\n", dbAlias ) ;    

    sqlrc = SQLFreeHandle( SQL_HANDLE_DBC, *pHdbc ) ;
    HANDLE_CHECK( SQL_HANDLE_DBC, *pHdbc, sqlrc, pHenv, pHdbc ) ;

    sqlrc = SQLFreeHandle( SQL_HANDLE_ENV,  *pHenv ) ;
    HANDLE_CHECK( SQL_HANDLE_ENV, *pHenv, sqlrc, pHenv, pHdbc ) ;

    return( 0 ) ;
}




/******************************************************************************
**          2.5 - StmtResultPrint - no more comments
******************************************************************************/
int StmtResultPrint( SQLHANDLE hstmt)
{   SQLRETURN   sqlrc = SQL_SUCCESS;
    int         rc = 0; 

    SQLSMALLINT i ; /* index */   
    SQLSMALLINT nResultCols ; /* variable for SQLNumResultCols */     
    
    SQLCHAR     colName[32] ;    /* variables for SQLDescribeCol  */
    SQLSMALLINT colNameLen ;    
    SQLSMALLINT colType ;
    SQLUINTEGER colSize ;
    SQLSMALLINT colScale ;
    
    SQLINTEGER colDataDisplaySize ; /* the max. size of the data */
    
    SQLINTEGER colDisplaySize[MAX_COLUMNS] ; /* the max. size of the column */

    struct
    {   SQLCHAR    * buff;
        SQLINTEGER len;
        SQLINTEGER buffLen;	
    } outData[MAX_COLUMNS];  /* var. to read the results */    
    
    /*--> 00003342.snippet */
    /* identify the output columns */    
    sqlrc = SQLNumResultCols( hstmt, &nResultCols ) ;
    STMT_HANDLE_CHECK( hstmt, sqlrc);
    /* 00003342.snippet <--*/

    printf("\n");
    for ( i = 0; i < nResultCols; i++ )
    {   /*-->00000581.snippet */
        sqlrc = SQLDescribeCol( hstmt,
                        ( SQLSMALLINT ) ( i + 1 ),
                        colName,
                        sizeof(colName),
                        &colNameLen,
                        &colType,
                        &colSize,
                        &colScale,
                        NULL ) ;
       /* 00000581.snippet <--*/
    
        STMT_HANDLE_CHECK( hstmt, sqlrc);
        /*-->00003359.snippet */
        /* get display size for column */
        sqlrc = SQLColAttribute( hstmt,
                         ( SQLSMALLINT ) ( i + 1 ),
                         SQL_DESC_DISPLAY_SIZE,
                         NULL,
                         0,
                         NULL,
                         &colDataDisplaySize ) ;
        STMT_HANDLE_CHECK( hstmt, sqlrc);
        /* 00003359.snippet <--*/

        /* set "column display size" to max of "column data display size",
           and "column name length". Plus at least one space between 
           columns.
        */	
        colDisplaySize[i] = max( colDataDisplaySize,
                                 colNameLen
                                ) + 1 ;

        /* print the column name */	
        printf( "%-*.*s",
                (int) colDisplaySize[i],
                (int) colDisplaySize[i],
                colName ) ;

        /* set "output data buffer length" to "column data display size".
           Plus one byte for null terminator.
        */
        outData[i].buffLen = colDataDisplaySize + 1;        	
	
        /* allocate memory to bind column */
        outData[i].buff = ( SQLCHAR * ) malloc( (int) outData[i].buffLen ) ;

       /*--> 00003329.snippet */ 
       /* bind columns to program vars, converting all types to CHAR */
        sqlrc = SQLBindCol( hstmt,
                    ( SQLSMALLINT ) ( i + 1 ),
                    SQL_C_CHAR,
                    outData[i].buff,
                    outData[i].buffLen,
                    &outData[i].len ) ;
        STMT_HANDLE_CHECK( hstmt, sqlrc);
        /* 00003329.snippet <--*/
    }
       

    printf( "\n" ) ;
    /*-->00000592.snippet */
    /* fetch each row and display */
    sqlrc = SQLFetch( hstmt ) ;
    if (sqlrc == SQL_NO_DATA_FOUND)
    {   printf("\nData not found.\n");
    }  
    /* 00000592.snippet <--*/ 
    while ( sqlrc == SQL_SUCCESS || sqlrc == SQL_SUCCESS_WITH_INFO )
    {   for ( i = 0; i < nResultCols; i++ )
        {   /* check for NULL data */
            if ( outData[i].len == SQL_NULL_DATA )
            {   printf( "%-*.*s",
                        (int) colDisplaySize[i],
                        (int) colDisplaySize[i],
                        "NULL" ) ;
            }
            else 
            {   /* print outData for this column */
                printf( "%-*.*s",
                        (int) colDisplaySize[i],
                        (int) colDisplaySize[i],
                        outData[i].buff ) ;
            }
        }                          /* for all columns in this row  */

        printf("\n");	
        sqlrc = SQLFetch( hstmt ) ;  
        STMT_HANDLE_CHECK( hstmt, sqlrc);	
    }                              /* while rows to fetch */

    /* free data buffers */
    for ( i = 0; i < nResultCols; i++ )
    {   free( outData[i].buff ) ;
    }
    
    return(rc);    
}