RETCODE static EnlistInDtc_1pipe()

in sql-odbc/src/opensearchenlist/msdtc_enlist.cpp [1006:1171]


RETCODE static EnlistInDtc_1pipe(void *conn, ITransaction *pTra,
                                 ITransactionDispenser *pDtc, int method) {
    CSTR func = "EnlistInDtc_1pipe";
    static IDtcToXaHelperSinglePipe *pHelper = NULL;
    ITransactionResourceAsync *pRes = NULL;
    IAsyncES *asdum;
    HRESULT res;
    DWORD dwRMCookie;
    XID xid;
    const char *xalibname = GetXaLibName();
    const char *xalibpath = GetXaLibPath();

    int recovLvl;
    char errmsg[256];
    char reason[128];

    if (!pHelper) {
        res = pDtc->QueryInterface(IID_IDtcToXaHelperSinglePipe,
                                   (void **)&pHelper);
        if (res != S_OK || !pHelper) {
            mylog("DtcToXaHelperSingelPipe get error %d\n", res);
            pHelper = NULL;
            return SQL_ERROR;
        }
    }
    res = (NULL != (asdum = new IAsyncES)) ? S_OK : E_FAIL;
    if (S_OK != res) {
        mylog("CoCreateInstance error %d\n", res);
        return SQL_ERROR;
    }

    recovLvl = EsDtc_is_recovery_available(conn, reason, sizeof(reason));
    switch (method) {
        case DTC_CHECK_BEFORE_LINK:
            if (0 == recovLvl) {
                snprintf(errmsg, sizeof(errmsg),
                         "%s is unavailable in distributed transactions",
                         reason);
                EsDtc_set_error(conn, errmsg, func);
                return SQL_ERROR;
            }
    }
    /*mylog("dllname=%s dsn=%s\n", xalibname, conn->connInfo.dsn); res = 0;*/
    char dtcname[1024];
    EsDtc_create_connect_string(conn, dtcname, sizeof(dtcname));

    bool confirmedRegkey = false, confirmingLink = false, xarmerr = false;
    char error_header[64];
    while (true) {
        res = pHelper->XARMCreate(dtcname, (char *)xalibname, &dwRMCookie);

        mylog("XARMcreate error code=%x (%d %d)\n", res, confirmedRegkey,
              confirmingLink);
        xarmerr = true;
        if (!confirmingLink)
            snprintf(error_header, sizeof(error_header),
                     "XARMcreate error code=%x", res);
        switch (res) {
            case S_OK:
                if (confirmingLink) {
                    switch (recovLvl) {
                        case 0:
                            snprintf(errmsg, sizeof(errmsg),
                                     "%s:%s is currently unavailable in "
                                     "distributed transactions",
                                     error_header, reason);
                            break;
                        case -1:
                            snprintf(
                                errmsg, sizeof(errmsg),
                                "%s:Possibly you connect to the database whose "
                                "authentication method is %s or ident",
                                error_header, reason);
                            break;
                        case 1:
                            snprintf(
                                errmsg, sizeof(errmsg),
                                "%s:Are you trying to connect to the database "
                                "whose authentication method is ident?",
                                error_header);
                            break;
                    }
                } else
                    xarmerr = false;
                break;
            case XACT_E_XA_TX_DISABLED:
                snprintf(errmsg, sizeof(errmsg),
                         "%s:Please enable XA transaction in MSDTC security "
                         "configuration",
                         error_header);
                break;
            case XACT_E_TMNOTAVAILABLE:
                snprintf(errmsg, sizeof(errmsg),
                         "%s:Please start Distributed Transaction Coordinator "
                         "service",
                         error_header);
                break;
            case E_FAIL:
                if (!confirmedRegkey) {
                    int retcode = regkeyCheck(xalibname, xalibpath);
                    confirmedRegkey = true;
                    if (retcode > 0)
                        continue;
                }
                switch (method) {
                    case DTC_CHECK_RM_CONNECTION:
                        if (!confirmingLink) {
                            confirmingLink = true;
                            strcat(dtcname, ";" KEYWORD_DTC_CHECK "=0");
                            continue;
                        }
                    default:
                        snprintf(errmsg, sizeof(errmsg),
                                 "%s:Failed to link with DTC service. Please "
                                 "look at the log of Event Viewer etc.",
                                 error_header);
                }
                break;
            case XACT_E_CONNECTION_DOWN:
                snprintf(errmsg, sizeof(errmsg),
                         "%s:Lost connection with DTC transaction "
                         "manager\nMSDTC has some trouble?",
                         error_header);
                break;
            default:
                snprintf(errmsg, sizeof(errmsg), "%s\n", error_header);
                break;
        }
        break;
    }
    if (xarmerr) {
        EsDtc_set_error(conn, errmsg, func);
        return SQL_ERROR;
    }

    res = pHelper->ConvertTridToXID((DWORD *)pTra, dwRMCookie, &xid);
    if (res != S_OK) {
        mylog("ConvertTridToXid error %d\n", res);
        return SQL_ERROR;
    }
    {
        char esxid[258];
        XidToText(xid, esxid);
        mylog("ConvertTridToXID -> %s\n", esxid);
    }
    asdum->SetXid(&xid);
    /* Create an IAsyncES instance by myself */
    /* DLLGetClassObject(GUID_IAsyncES, IID_ITransactionResourceAsync, (void **)
     * &asdum); */

    asdum->SetHelper(pHelper, dwRMCookie);
    res = pHelper->EnlistWithRM(dwRMCookie, pTra, asdum, &asdum->enlist);
    if (res != S_OK) {
        mylog("EnlistWithRM error %d\n", res);
        pHelper->ReleaseRMCookie(dwRMCookie, TRUE);
        return SQL_ERROR;
    }

    mylog("asdum=%p start transaction\n", asdum);
    asdum->SetConnection(conn);
    LIFELOCK_ACQUIRE;
    EsDtc_set_async(conn, asdum);
    LIFELOCK_RELEASE;

    return SQL_SUCCESS;
}