// MySQL-ADOTest.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include <format>
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF", "EndOfFile")

void PrintComError(_com_error& e) {
    _bstr_t bstrSource(e.Source());
    _bstr_t bstrDescription(e.Description());

    // Print Com errors.  
    std::wcout << "Error\n" << "\tCode = " << e.Error() << "\n\tCode meaning = " << e.ErrorMessage() << "\n\tSource = " << (LPCSTR)bstrSource << "\n\tDescription = " << (LPCSTR)bstrDescription << std::endl;
}

int main(int argc, char *argv[])
{
    if (FAILED(::CoInitialize(NULL)))
        return -1;

    _bstr_t connStr;
    if (argc == 2) {
        connStr = std::format("Driver={{MySQL ODBC {} Unicode Driver}};Server=localhost;Database=drivertest;Uid=testuser;Password=A1s2d3f4;Min Pool Size=5;Max Pool Size=500;Connect Timeout=8;", argv[1]).c_str();
    }
    else {
        std::cout << "Please provide the driver version" << std::endl;
        return 1;
    }

    _ConnectionPtr conn = NULL;
    HRESULT hr = conn.CreateInstance(__uuidof(Connection));
    if (FAILED(hr)) {
        std::cout << "Could not create ADODB connection" << std::endl;
        return 1;
    }

    try
    {
        
        hr = conn->Open(connStr, "", "", adConnectUnspecified);

        _CommandPtr getLockCommand = NULL;
        getLockCommand.CreateInstance(__uuidof(Command));
        getLockCommand->CommandType = adCmdText;
        getLockCommand->CommandText = _bstr_t("SELECT GET_LOCK('MyLock', 60000) as GotLock;");

        _RecordsetPtr getRecSet = NULL;
        getRecSet.CreateInstance(__uuidof(Recordset));
        getRecSet->PutRefActiveConnection(conn);

        getLockCommand->CommandTimeout = 60;
        getLockCommand->PutRefActiveConnection(conn);

        hr = getRecSet.CreateInstance(__uuidof(Recordset));
        hr = getRecSet->Open(_variant_t((IDispatch*)getLockCommand, true), vtMissing, adOpenForwardOnly, adLockReadOnly, 0);
        if (SUCCEEDED(hr)) {
            std::cout << "Got the lock" << std::endl;
        }

        _CommandPtr releaseLockCommand = NULL;
        releaseLockCommand.CreateInstance(__uuidof(Command));
        releaseLockCommand->CommandType = adCmdText;
        releaseLockCommand->CommandText = _bstr_t("SELECT RELEASE_LOCK('MyLock') as ReleasedLock;");

        _RecordsetPtr releaseRecSet = NULL;
        releaseRecSet.CreateInstance(__uuidof(Recordset));
        releaseRecSet->PutRefActiveConnection(conn);

        releaseLockCommand->CommandTimeout = 60;
        releaseLockCommand->PutRefActiveConnection(conn);

        hr = releaseRecSet.CreateInstance(__uuidof(Recordset));
        hr = releaseRecSet->Open(_variant_t((IDispatch*)releaseLockCommand, true), vtMissing, adOpenForwardOnly, adLockReadOnly, 0);
        if (SUCCEEDED(hr)) {
            std::wcout << "Release Lock called" << std::endl;

            // Ensure at top of recordset.  
            releaseRecSet->MoveFirst();

            // If EOF is true, then no data and skip print loop.  
            if (releaseRecSet->EndOfFile)
                std::wcout << "Empty recordset" << std::endl;
            else {
                // Define strings for output conversions.  Initialize to first record's values.  
                _bstr_t isReleased;
                
                // Enumerate Recordset and print from each.  
                while (!(releaseRecSet->EndOfFile)) {
                    // Convert variant string to convertable string type.  
                    isReleased = releaseRecSet->Fields->GetItem("ReleasedLock")->Value;
                    std::wcout << "Release result: " << isReleased << std::endl;
                    releaseRecSet->MoveNext();
                }
            }
        }
    }
    catch (_com_error& e)
    {
        PrintComError(e);
    }

    ::CoUninitialize();
}

// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu

// Tips for Getting Started: 
//   1. Use the Solution Explorer window to add/manage files
//   2. Use the Team Explorer window to connect to source control
//   3. Use the Output window to see build output and other messages
//   4. Use the Error List window to view errors
//   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
//   6. In the future, to open this project again, go to File > Open > Project and select the .sln file
