EndDateLogOdbcTransaction

Commit or roll back the current transaction on a DATE_LOG_HANDLE's ODBC connection

Overview

EndDateLogOdbcTransaction commits or rolls back the current transaction on the ODBC connection identified by OdbcLevel, via SQLEndTran() (wrapped by odbc.c’s OdbcEndTranImpl()). Typically used after autocommit has been disabled through SetDateLogOdbcConnectAttr, to group multiple statements into a single transaction.

Purpose

Gives the caller explicit control over when work performed on a date log’s ODBC connection becomes permanent (commit) or is discarded (roll back).

Key Features

Function Signature


HRESULT _Must_inspect_result_ _Success_(SUCCEEDED(return)) EndDateLogOdbcTransaction(
    _In_ DATE_LOG_HANDLE      hDateLogHandle,
    _In_ DATE_LOG_ODBC_LEVEL  OdbcLevel,
    _In_ BOOL                 bCommit
);

Parameters

hDateLogHandle

[In] DATE_LOG_HANDLE

A valid DATE_LOG_HANDLE, DATE_RANGE_HANDLE, or HOLIDAYS_HANDLE that owns the connection.

  • NULL: not documented as accepted; always pass a valid handle
  • Ownership: unchanged; the handle is not closed or consumed
  • Lifetime: must remain valid for the duration of the call. The connection belongs to the handle and is closed with it by CloseDateLogHandle
OdbcLevel

[In] DATE_LOG_ODBC_LEVEL

Which connection to target: DATE_LOG_ODBC_1 through DATE_LOG_ODBC_4.

  • A connection must already have been established at this level with ConnectDateLogHandleToOdbcDatabase; otherwise HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE_STATE) is returned
bCommit

[In] BOOL

Selects the action for the open transaction.

  • TRUE — commit (SQL_COMMIT)
  • FALSE — roll back (SQL_ROLLBACK)

Return Values

S_OK

Transaction committed/rolled back successfully.

HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE_STATE)

No connection established yet at the requested OdbcLevel.

HRESULT_FROM_WIN32(ERROR_INVALID_DATA)

SQLEndTran() failed.

These are the only codes documented for this function. Always test the result with FAILED()/SUCCEEDED(); the function is marked _Must_inspect_result_.

Remarks

Ordering

FetchDateLogHandleToOdbcDatabase is documented to commit or roll back the connection’s transaction itself, if autocommit is off, on completion or failure; consult that page before calling this function for the same work.

Thread Safety

The existing documentation does not describe locking for this function beyond that it operates through the handle’s connection context. Do not end a transaction on a level while another thread is issuing statements on the same level, because a transaction belongs to the connection, not to a thread. Duplicates (see DuplicateDateLogHandle) share the same connections.

Handle Lifetime and Reference Counting

The function does not change reference counts or close the connection; the connection stays open after commit/rollback and is closed when the last handle referencing the context is closed with CloseDateLogHandle.

Sample Code

The example connects ODBC level 1, disables autocommit, performs a placeholder unit of work, and then commits (or rolls back) with EndDateLogOdbcTransaction. All parameters and handles are freed or closed on every path. Replace the connection values with your own and load your holiday data as noted in the code.


#include <stdio.h>
#include "datelog.h"


static HRESULT BuildSampleDateLog(HOLIDAYS_HANDLE hHolidays, DATE_LOG_HANDLE *phDateLog)
{
    DATE_LOG_HANDLE  hDateLog = NULL;
    DATE_ITEM_HANDLE hStart   = NULL;
    DATE_ITEM_HANDLE hEnd     = NULL;
    SYSTEMTIME       stStart  = { 0 };
    SYSTEMTIME       stEnd    = { 0 };
    FILETIME         ftStart  = { 0 };
    FILETIME         ftEnd    = { 0 };
    HRESULT          hr       = E_FAIL;

    *phDateLog = NULL;

    /* Tuesday 2 January 2024 through Wednesday 31 January 2024 (both market days). */
    stStart.wYear = 2024; stStart.wMonth = 1; stStart.wDay = 2;
    stEnd.wYear   = 2024; stEnd.wMonth   = 1; stEnd.wDay   = 31;
    if (!SystemTimeToFileTime(&stStart, &ftStart) || !SystemTimeToFileTime(&stEnd, &ftEnd)) {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, hHolidays, &hDateLog, HandleIsForDatelog);
    if (FAILED(hr)) {
        return hr;
    }

    hr = InitializeDateItem(hDateLog, &ftStart, NULL, &hStart);
    if (SUCCEEDED(hr)) {
        hr = InitializeDateItem(hDateLog, &ftEnd, NULL, &hEnd);
    }
    if (SUCCEEDED(hr)) {
        /* No file context: generate the contiguous range between hStart and hEnd. */
        hr = LoadDateLogHandle(NULL, hStart, hEnd, hDateLog, NULL, 0);
    }

    FreeDateItem(hEnd);
    FreeDateItem(hStart);

    if (FAILED(hr)) {
        CloseDateLogHandle(hDateLog);
        return hr;
    }

    *phDateLog = hDateLog;
    return S_OK;
}

static HRESULT ConnectLevel1(DATE_LOG_HANDLE hDateLog)
{
    PODBC_CONNECT_PARAMS pParams = NULL;
    HRESULT              hr      = E_FAIL;

    hr = InitializeDateLogHandleOdbc(hDateLog, DATE_LOG_ODBC_1);
    if (FAILED(hr)) {
        return hr;
    }

    hr = InitializeOdbcConnectParams(&pParams);
    if (FAILED(hr)) {
        return hr;
    }

    hr = pParams->AddParam(pParams, "Driver", "{ODBC Driver 17 for SQL Server}");
    if (SUCCEEDED(hr)) {
        hr = pParams->AddParam(pParams, "Server", "localhost\\SQLEXPRESS");
    }
    if (SUCCEEDED(hr)) {
        hr = pParams->AddParam(pParams, "Database", "MyDatabase");
    }
    if (SUCCEEDED(hr)) {
        pParams->Trusted_Connection = ODBC_TRUE;
        hr = ConnectDateLogHandleToOdbcDatabase(hDateLog, pParams, DATE_LOG_ODBC_1);
    }

    /* The library does not retain pParams. */
    if (FAILED(FreeOdbcConnectParams(pParams)) && SUCCEEDED(hr)) {
        hr = E_FAIL;
    }
    return hr;
}

int main(void)
{
    HOLIDAYS_HANDLE hHolidays = NULL;
    DATE_LOG_HANDLE hDateLog  = NULL;
    HRESULT         hr        = E_FAIL;
    HRESULT         hrEnd     = E_FAIL;
    int             rc        = 1;

    /* Holidays handle. Populate it with your market holiday data (see
       LoadDateLogHandle) before building date logs; that step is application specific. */
    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, NULL, &hHolidays, HandleIsForHolidays);
    if (FAILED(hr)) {
        printf("InitializeDateLogHandle failed for holidays: 0x%08lX\n", (unsigned long)hr);
        return 1;
    }

    hr = BuildSampleDateLog(hHolidays, &hDateLog);
    if (FAILED(hr)) {
        printf("BuildSampleDateLog failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    hr = ConnectLevel1(hDateLog);
    if (FAILED(hr)) {
        printf("Connecting ODBC level 1 failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    /* Group several statements into one transaction by turning autocommit off. */
    hr = SetDateLogOdbcConnectAttr(hDateLog, DATE_LOG_ODBC_1, SQL_ATTR_AUTOCOMMIT,
                                   (SQLPOINTER)(ULONG_PTR)SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
    if (FAILED(hr)) {
        printf("SetDateLogOdbcConnectAttr failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    /* ... perform the ODBC work for the transaction on level 1 here ... */
    hr = S_OK;

    /* Commit when the work succeeded, otherwise roll back. */
    hrEnd = EndDateLogOdbcTransaction(hDateLog, DATE_LOG_ODBC_1, SUCCEEDED(hr) ? TRUE : FALSE);
    if (FAILED(hrEnd)) {
        printf("EndDateLogOdbcTransaction failed: 0x%08lX\n", (unsigned long)hrEnd);
        goto cleanup;
    }

    printf("Transaction %s.\n", SUCCEEDED(hr) ? "committed" : "rolled back");
    rc = SUCCEEDED(hr) ? 0 : 1;

cleanup:
    /* Closing the handle also closes its ODBC connection. */
    if (hDateLog != NULL && FAILED(CloseDateLogHandle(hDateLog))) {
        rc = 1;
    }
    if (FAILED(CloseDateLogHandle(hHolidays))) {
        rc = 1;
    }
    return rc;
}

See Also