/******************************************************************************
**
** Source File Name = samputil.c  1.3
**
** Licensed Materials - Property of IBM
**
** (C) COPYRIGHT International Business Machines Corp. 1995, 1999
** All Rights Reserved.
**
** US Government Users Restricted Rights - Use, duplication or
** disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
**
**
**    PURPOSE :
**    - contains various sample functions, used by most other samples:
**       - check_error
**       - DBconnect
**       - prompted_connect
**       - print_connect_info
**       - print_error
**       - print_results
**       - check_error
**       - terminate
**
** 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 "samputil.h"

#define MAXCOLS 255

#ifndef max
  #define max(a,b) (a > b ? a : b)
#endif

/*
 * Global Variables for user id and password, defined in main module.
 * To keep samples simple, not a recommended practice.
 * The INIT_UID_PWD macro is used to initialize these variables.
 */
SQLCHAR server[SQL_MAX_DSN_LENGTH + 1] ;
SQLCHAR uid[MAX_UID_LENGTH + 1] ;
SQLCHAR pwd[MAX_PWD_LENGTH + 1] ;

/* check_error - calls print_error(), checks severity of return code */

SQLRETURN check_error( SQLSMALLINT htype, /* A handle type identifier */
                       SQLHANDLE   hndl,  /* A handle */
                       SQLRETURN   frc,   /* Return code to be included with error msg  */
                       int         line,  /* Used for output message, indcate where     */
                       char *      file   /* the error was reported from  */
                     ) {

    print_error( htype, hndl, frc, line, file ) ;

    switch ( frc ) {
      case SQL_SUCCESS:
        break ;
      case SQL_INVALID_HANDLE:
        printf( "\n>------ ERROR Invalid Handle --------------------------\n" ) ;
      case SQL_ERROR:
        printf( "\n>--- FATAL ERROR, Attempting to rollback transaction --\n" ) ;
        if ( SQLEndTran( htype, hndl, SQL_ROLLBACK ) != SQL_SUCCESS )
           printf( ">Rollback Failed, Exiting application\n" ) ;
        else
           printf( ">Rollback Successful, Exiting application\n" ) ;
        return( terminate( hndl, frc ) ) ;
      case SQL_SUCCESS_WITH_INFO:
        printf( "\n> ----- Warning Message, application continuing ------- \n" ) ;
        break ;
      case SQL_NO_DATA_FOUND:
        printf( "\n> ----- No Data Found, application continuing --------- \n" ) ;
        break ;
      default:
        printf( "\n> ----------- Invalid Return Code --------------------- \n" ) ;
        printf( "> --------- Attempting to rollback transaction ---------- \n" ) ;
        if ( SQLEndTran( htype, hndl, SQL_ROLLBACK ) != SQL_SUCCESS )
           printf( ">Rollback Failed, Exiting application\n" ) ;
        else
           printf( ">Rollback Successful, Exiting application\n" ) ;
        return( terminate( hndl, frc ) ) ;
    }

    return ( frc ) ;

}

/* connect without prompt */

SQLRETURN DBconnect( SQLHANDLE henv,
                     SQLHANDLE * hdbc
                   ) {

    /* allocate a connection handle */
    if ( SQLAllocHandle( SQL_HANDLE_DBC,
                         henv,
                         hdbc
                       ) != SQL_SUCCESS ) {
        printf( ">---ERROR while allocating a connection handle-----\n" ) ;
        return( SQL_ERROR ) ;
    }

    /* Set AUTOCOMMIT OFF */
    if ( SQLSetConnectAttr( * hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            ( void * ) SQL_AUTOCOMMIT_OFF, SQL_NTS
                          ) != SQL_SUCCESS ) {
        printf( ">---ERROR while setting AUTOCOMMIT OFF ------------\n" ) ;
        return( SQL_ERROR ) ;
    }

    if ( SQLConnect( * hdbc,
                     server, SQL_NTS,
                     uid,    SQL_NTS,
                     pwd,    SQL_NTS
                   ) != SQL_SUCCESS ) {
        printf( ">--- Error while connecting to database: %s -------\n",
                server
              ) ;
        SQLDisconnect( * hdbc ) ;
        SQLFreeHandle( SQL_HANDLE_DBC, * hdbc ) ;
        return( SQL_ERROR ) ;
    }
    else      /* Print Connection Information */
        printf( ">Connected to %s\n", server ) ;

    return( SQL_SUCCESS ) ;

}

/* print connection information */

SQLRETURN print_connect_info( SQLHANDLE hdbc ) {

    SQLCHAR     buffer[255] ;
    SQLSMALLINT outlen ;
    SQLRETURN   rc ;

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

    rc = SQLGetInfo( hdbc, SQL_DATA_SOURCE_NAME, buffer, 255, &outlen ) ;
    CHECK_HANDLE( SQL_HANDLE_DBC, hdbc, rc ) ;
    printf( "Connected to Server: %s\n", buffer ) ;

    rc = SQLGetInfo( hdbc, SQL_DATABASE_NAME, buffer, 255, &outlen ) ;
    CHECK_HANDLE( SQL_HANDLE_DBC, hdbc, rc ) ;
    printf( " Database Name: %s\n", buffer ) ;

    rc = SQLGetInfo( hdbc, SQL_SERVER_NAME, buffer, 255, &outlen ) ;
    CHECK_HANDLE( SQL_HANDLE_DBC, hdbc, rc ) ;
    printf( " Instance Name: %s\n", buffer ) ;

    rc = SQLGetInfo( hdbc, SQL_DBMS_NAME, buffer, 255, &outlen ) ;
    CHECK_HANDLE( SQL_HANDLE_DBC, hdbc, rc ) ;
    printf( "     DBMS Name: %s\n", buffer ) ;

    rc = SQLGetInfo( hdbc, SQL_DBMS_VER, buffer, 255, &outlen ) ;
    CHECK_HANDLE( SQL_HANDLE_DBC, hdbc, rc ) ;
    printf( "  DBMS Version: %s\n", buffer ) ;

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

    return( rc ) ;

}

/*--> SQLL1X32.SCRIPT */
/* print_error - calls SQLGetDiagRec(), displays SQLSTATE and message **
**             - called by check_error                                */

SQLRETURN print_error( SQLSMALLINT htype, /* A handle type identifier */
                       SQLHANDLE   hndl,  /* A handle */
                       SQLRETURN   frc,   /* Return code to be included with error msg  */
                       int         line,  /* Used for output message, indcate where     */
                       char *      file   /* the error was reported from  */
                     ) {

    SQLCHAR     buffer[SQL_MAX_MESSAGE_LENGTH + 1] ;
    SQLCHAR     SQLSTATE[SQL_SQLSTATE_SIZE + 1] ;
    SQLINTEGER  sqlcode ;
    SQLSMALLINT length, i ;

    printf( ">--- ERROR -- RC = %d Reported from %s, line %d ------------\n",
            frc,
            file,
            line
          ) ;

    i = 1 ;
    while ( SQLGetDiagRec( htype,
                           hndl,
                           i,
                           SQLSTATE,
                           &sqlcode,
                           buffer,
                           SQL_MAX_MESSAGE_LENGTH + 1,
                           &length
                         ) == SQL_SUCCESS ) {
       printf( "         SQLSTATE: %s\n", SQLSTATE ) ;
       printf( "Native Error Code: %ld\n", sqlcode ) ;
       printf( "%s \n", buffer ) ;
       i++ ;
    }

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

    return( SQL_ERROR ) ;

}
/*<-- */

/*--> SQLL1X10.SCRIPT */
/* print_results */

SQLRETURN print_results( SQLHANDLE hstmt ) {

    SQLCHAR     colname[32] ;
    SQLSMALLINT coltype ;
    SQLSMALLINT colnamelen ;
    SQLSMALLINT nullable ;
    SQLUINTEGER collen[MAXCOLS] ;
    SQLSMALLINT scale ;
    SQLINTEGER  outlen[MAXCOLS] ;
    SQLCHAR *   data[MAXCOLS] ;
    SQLCHAR     errmsg[256] ;
    SQLRETURN   rc ;
    SQLSMALLINT nresultcols, i ;
    SQLINTEGER  displaysize ;

    rc = SQLNumResultCols( hstmt, &nresultcols ) ;
    CHECK_HANDLE( SQL_HANDLE_STMT, hstmt, rc ) ;
    if( rc != SQL_SUCCESS )
    {
        return( rc );
    }
    for ( i = 0; i < nresultcols; i++ ) {
        SQLDescribeCol( hstmt,
                        ( SQLSMALLINT ) ( i + 1 ),
                        colname,
                        sizeof(colname),
                        &colnamelen,
                        &coltype,
                        &collen[i],
                        &scale,
                        NULL
                      ) ;
        /* get display length for column */
        SQLColAttribute( hstmt,
                         ( SQLSMALLINT ) ( i + 1 ),
                         SQL_DESC_DISPLAY_SIZE,
                         NULL,
                         0,
                         NULL,
                         &displaysize
                       ) ;

        /*
         Set column length to max of display length,
         and column name length. Plus one byte for
         null terminator.
        */
        collen[i] = max( displaysize,
                         strlen( ( char * ) colname )
                       ) + 1 ;

        printf( "%-*.*s",
                ( int ) collen[i],
                ( int ) collen[i],
                colname
              ) ;

        /* allocate memory to bind column */
        data[i] = ( SQLCHAR * ) malloc( ( int ) collen[i] ) ;

        /* bind columns to program vars, converting all types to CHAR */
        SQLBindCol( hstmt,
                    ( SQLSMALLINT ) ( i + 1 ),
                    SQL_C_CHAR,
                    data[i],
                    collen[i],
                    &outlen[i]
                  ) ;
    }

    printf( "\n" ) ;
    /* display result rows */
    rc = SQLFetch( hstmt ) ;
    while ( (rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO) ) {

        errmsg[0] = '\0' ;
        for ( i = 0; i < nresultcols; i++ ) {
            /* Check for NULL data */
            if ( outlen[i] == SQL_NULL_DATA )
               printf( "%-*.*s",
                       ( int ) collen[i],
                       ( int ) collen[i],
                       "NULL"
                     ) ;
            else { /* Build a truncation message for any columns truncated */
               if ( outlen[i] >= collen[i] ) {
                  sprintf( ( char * ) errmsg + strlen( ( char * ) errmsg ),
                           "%d chars truncated, col %d\n",
                           ( int ) outlen[i] - collen[i] + 1,
                           i + 1
                         ) ;
               }
               /* Print column */
               printf( "%-*.*s",
                       ( int ) collen[i],
                       ( int ) collen[i],
                       data[i]
                     ) ;
            }
        }                          /* for all columns in this row  */

        printf( "\n%s", errmsg ) ; /* print any truncation messages */
        rc = SQLFetch( hstmt ) ;    	
    }                              /* while rows to fetch */
    if ( rc != SQL_NO_DATA_FOUND )
    {
        CHECK_HANDLE( SQL_HANDLE_STMT, hstmt, rc );
    }   


    /* free data buffers */
    for ( i = 0; i < nresultcols; i++ ) {
        free( data[i] ) ;
    }

    return( SQL_SUCCESS ) ;

}                               /* end print_results */
/*<-- */

/* prompted_connect - prompt for connect options and connect */

SQLRETURN prompted_connect( SQLHANDLE henv,
                            SQLHANDLE * hdbc
                          ) {

    /* allocate a connection handle     */
    if ( SQLAllocHandle( SQL_HANDLE_DBC,
                         henv,
                         hdbc
                       ) != SQL_SUCCESS ) {
        printf( ">---ERROR while allocating a connection handle-----\n" ) ;
        return( SQL_ERROR ) ;
    }

    /* Set AUTOCOMMIT OFF */
    if ( SQLSetConnectAttr( * hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            ( void * ) SQL_AUTOCOMMIT_OFF, SQL_NTS
                          ) != SQL_SUCCESS ) {
       printf( ">---ERROR while setting AUTOCOMMIT OFF ------------\n" ) ;
       return( SQL_ERROR ) ;
    }

    printf( ">Enter Server Name:\n" ) ;
    gets( ( char * ) server ) ;
    printf( ">Enter User Name:\n" ) ;
    gets( ( char * ) uid ) ;
    printf( ">Enter Password:\n" ) ;
    gets( ( char * ) pwd ) ;

    if ( SQLConnect( * hdbc,
                     server, SQL_NTS,
                     uid,    SQL_NTS,
                     pwd,    SQL_NTS
                   ) != SQL_SUCCESS ) {
        printf( ">--- ERROR while connecting to %s -------------\n",
                server
              ) ;
        
        SQLDisconnect( * hdbc ) ;
        SQLFreeHandle( SQL_HANDLE_DBC, * hdbc ) ;
        return( SQL_ERROR ) ;
    }
    else              /* Print Connection Information */
        printf( "Successful Connect to %s\n", server ) ;

    return( SQL_SUCCESS ) ;

}

/* terminate and free environment handle */

SQLRETURN terminate( SQLHANDLE henv,
                     SQLRETURN rc
                   ) {

    SQLRETURN lrc ;

    printf( ">Terminating ....\n" ) ;
    print_error( SQL_HANDLE_ENV,
                 henv,
                 rc,
                 __LINE__,
                 __FILE__
               ) ;

    /* Free environment handle */
    if ( ( lrc = SQLFreeHandle( SQL_HANDLE_ENV, henv ) ) != SQL_SUCCESS )
       print_error( SQL_HANDLE_ENV,
                    henv,
                    lrc,
                    __LINE__,
                    __FILE__
                  ) ;

    return( rc ) ;

}