#include <windows.h>
#include <sqlext.h>
#include <string>


#define CHECK_RESULT_AND_RETURN_ON_ERROR(funcName) \
    if (SQL_SUCCESS != result && SQL_SUCCESS_WITH_INFO != result) {\
        printf(#funcName " failed!");\
        return 0;\
    }

int main() {


    SQLHANDLE sqlhenv{};
    auto result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlhenv);
    CHECK_RESULT_AND_RETURN_ON_ERROR(SQLAllocHandle(SQL_HANDLE_ENV))
    
    result = SQLSetEnvAttr(sqlhenv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
    CHECK_RESULT_AND_RETURN_ON_ERROR(SQLSetEnvAttr)


    SQLHDBC sqlhdbc{};
    result = SQLAllocHandle(SQL_HANDLE_DBC, sqlhenv, &sqlhdbc);
    CHECK_RESULT_AND_RETURN_ON_ERROR(SQLAllocHandle(SQL_HANDLE_DBC))
    

    result = SQLConnect(sqlhdbc, const_cast<SQLWCHAR*>(L"test"), SQL_NTS, nullptr, SQL_NTS, nullptr, SQL_NTS);
    CHECK_RESULT_AND_RETURN_ON_ERROR(SQLConnect)

    std::wstring_view sqlQuery{L"SELECT * FROM test WHERE name = ?"};

    char searchValue[1000]{};
    strcpy_s(searchValue, "test 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
    const std::string_view viewSearchValue{searchValue};


    for (int i = 0; i < 100000; ++i) {

        SQLHANDLE hStmt{};

        result = SQLAllocHandle(SQL_HANDLE_STMT, sqlhdbc, &hStmt);
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLAllocHandle)


        result = SQLPrepare(hStmt, const_cast<SQLWCHAR*>(sqlQuery.data()), sqlQuery.size());
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLExecDirectW)

        SQLINTEGER cbValue{SQL_NTSL};

        
        result = SQLBindParameter(hStmt,
            1,
            SQL_PARAM_INPUT,
            SQL_C_CHAR,
            SQL_VARCHAR,
            1000,
            0,
            (void*)searchValue,
            viewSearchValue.size(),
            &cbValue);
         
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLBindParameter)

        result = SQLExecDirect(hStmt, const_cast<SQLWCHAR*>(sqlQuery.data()), sqlQuery.size());
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLExecDirectW)

        SQLINTEGER cRowCount{};
        result = SQLRowCount(hStmt, &cRowCount);
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLRowCount)

        result = SQLFreeStmt(hStmt, SQL_CLOSE);
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLFreeStmt(SQL_CLOSE))

        result = SQLFreeStmt(hStmt, SQL_UNBIND);
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLFreeStmt(SQL_UNBIND))

        result = SQLFreeStmt(hStmt, SQL_RESET_PARAMS);
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLFreeStmt(SQL_RESET_PARAMS))


        result = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
        CHECK_RESULT_AND_RETURN_ON_ERROR(SQLFreeHandle)

    }

    // SQLWCHAR state[6]{};
    // SQLINTEGER error{};
    // SQLWCHAR message[1024];
    // SQLSMALLINT sizeMessage;
    // SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, 1, state, &error, message, _countof(message), &sizeMessage);
    

}