#include <stdio.h>
#include <sql.h>
#include <sqlext.h>

int free_handle(SQLHANDLE* pHandle, int type)
{
    if(*pHandle != NULL) {
        if(type == SQL_HANDLE_DBC) {
            SQLDisconnect(*pHandle);
        }
        SQLFreeHandle(type, *pHandle);
        *pHandle = NULL;
    }
    return 1;
}

int check_success(SQLRETURN rc, const char* f)
{
    if(!SQL_SUCCEEDED(rc)) {
        fprintf(stderr, "%s returned %d\n", f, rc);
        return 0;
    }
    return 1;
}

int print_prepared_stmt_count(SQLHANDLE dbc, const char* state)
{
    ULONG count = 0;
    SQLHANDLE stmt = NULL;
    int ret = 1;
    if(
        !check_success(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), "SQLAllocHandle(SQL_HANDLE_STMT)") ||
        !check_success(SQLExecDirect(stmt, (SQLCHAR*)"SHOW GLOBAL STATUS LIKE 'Prepared_stmt_count'", SQL_NTS), "SQLExecDirect") ||
        !check_success(SQLFetch(stmt), "SQLFetch") ||
        !check_success(SQLGetData(stmt, 2, SQL_C_ULONG, &count, sizeof(count), NULL), "SQLGetData")
    ) {
        fprintf(stderr, "%s - Couldn't determing Prepared_stmt_count\n", state);
        ret = 0;
    } else {
        printf("%s - %zu\n", state, count);
    }
    free_handle(&stmt, SQL_HANDLE_STMT);
    return ret;
}


int main(int argc, char** argv)
{
    SQLHANDLE env = NULL;
    SQLHANDLE dbc = NULL;
    SQLHANDLE stmt = NULL;
    int ret = 0;
    SQLCHAR connection_string[] = "";
    SQLCHAR username_string[] = "";
    SQLCHAR password_string[] = "";

    if(
        !check_success(SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env), "SQLAllocHandle(SQL_HANDLE_ENV)") ||
        !check_success(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0), "SQLSetEnvAttr") ||
        !check_success(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), "SQLAllocHandle(SQL_HANDLE_DBC)") ||
        !check_success(SQLSetConnectAttr(dbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER*)15, 0), "SQLSetConnectAttr") ||
        !check_success(SQLConnect(dbc, connection_string, SQL_NTS, username_string, SQL_NTS, password_string, SQL_NTS), "SQLConnect") ||
        !print_prepared_stmt_count(dbc, "Initial") ||
        !print_prepared_stmt_count(dbc, "After SQLExecDirect") ||
        !check_success(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), "SQLAllocHandle(SQL_HANDLE_STMT)") ||
        !check_success(SQLPrepare(stmt, (SQLCHAR*)"SELECT 1", SQL_NTS), "SQLPrepare") ||
        !print_prepared_stmt_count(dbc, "After SQLPrepare") ||
        !check_success(SQLExecute(stmt), "SQLExecute") ||
        !print_prepared_stmt_count(dbc, "After SQLExecute") ||
        !check_success(SQLFetch(stmt), "SQLFetch") ||
        !check_success(SQLCloseCursor(stmt), "SQLCloseCursor") ||
        !print_prepared_stmt_count(dbc, "After SQLCloseCursor") ||
        !free_handle(&stmt, SQL_HANDLE_STMT) ||
        !print_prepared_stmt_count(dbc, "After SQLFreeHandle") ||
        !check_success(SQLDisconnect(dbc), "SQLDisconnect") ||
        !check_success(SQLConnect(dbc, connection_string, SQL_NTS, username_string, SQL_NTS, password_string, SQL_NTS), "SQLConnect") ||
        !print_prepared_stmt_count(dbc, "After Reconnect")
    ) {
        ret = 1;
    }
    free_handle(&stmt, SQL_HANDLE_STMT);
    free_handle(&dbc, SQL_HANDLE_DBC);
    free_handle(&env, SQL_HANDLE_ENV);
    return ret;
}
