SQL_DATE_BULK

A structure for bulk-transferring date information to and from SQL Server via ODBC

Overview

SQL_DATE_BULK is a structure that facilitates bulk data transfer of date information to and from SQL Server via ODBC (Open Database Connectivity). This structure is designed to optimize performance when performing bulk operations on large numbers of dates, minimizing the overhead of individual row transfers.

The structure provides a container for date data that can be bound to ODBC parameters for parameterized queries or bulk insert/update operations. It is particularly useful when loading large date collections into database tables or extracting dates from database tables in batch mode.

Structure Definition

The SQL_DATE_BULK structure is defined in datelog.h as follows:


typedef struct _SQL_DATE_BULK {
    DWORD           RecordCount;        /* Number of date records in this bulk transfer */
    DWORD           MaxRecordCount;     /* Maximum capacity of the bulk buffer */
    PSQL_DATE_RECORD Records;           /* Array of SQL date records */
    SQLLEN         *RowStatusArray;    /* Array of row operation statuses (SQLLEN) */
    HRESULT         LastOperationStatus; /* HRESULT of the last bulk operation */
} SQL_DATE_BULK, *PSQL_DATE_BULK;
The SQL_DATE_RECORD structure within this array contains individual date information in a format suitable for SQL Server operations, typically with FILETIME or SYSTEMTIME representations depending on the SQL data type.

Structure Members

RecordCount DWORD

The number of date records currently present in the bulk transfer buffer. This value should not exceed MaxRecordCount.

MaxRecordCount DWORD

The maximum number of date records that can be stored in the current allocation of the Records array. When RecordCount would exceed this value, the array is automatically resized.

Records PSQL_DATE_RECORD

A pointer to an array of SQL_DATE_RECORD structures, each containing the date information for a single row in the bulk operation. The array has at least RecordCount valid elements.

RowStatusArray SQLLEN*

An optional array of SQLLEN values indicating the status of each row operation after a bulk fetch or insert. Elements contain ODBC row status values or error codes.

LastOperationStatus HRESULT

The HRESULT status code from the most recent bulk operation performed with this structure. Provides diagnostic information about the success or failure of the operation.

Remarks

Always use library functions to create, populate, and free SQL_DATE_BULK structures. Manual manipulation of the Records array may cause data corruption or memory leaks.

Usage Patterns

Bulk Fetching Dates from Database

Use SQL_DATE_BULK to retrieve multiple rows from a date table in a single operation:


SQL_DATE_BULK bulk = {0};
DATE_LOG_HANDLE hDateLog = NULL;

/* Fetch up to 1000 date records from the database */
HRESULT hr = FetchDateLogHandleToOdbcDatabase(
    hDateLog,
    &bulk,      /* Output bulk structure */
    1000        /* Max records to fetch */
);

if (SUCCEEDED(hr)) {
    printf("Fetched %lu date records\n", bulk.RecordCount);
    
    /* Process the fetched records */
    for (DWORD i = 0; i < bulk.RecordCount; i++) {
        /* Access bulk.Records[i] */
        if (bulk.RowStatusArray != NULL) {
            SQLLEN status = bulk.RowStatusArray[i];
            if (status == SQL_ROW_SUCCESS) {
                /* Process successful record */
            }
        }
    }
}

Bulk Inserting Dates into Database

Populate a SQL_DATE_BULK structure and insert multiple records:


SQL_DATE_BULK bulk = {0};
DATE_LOG_HANDLE hDateLog = NULL;

/* Populate the bulk structure with dates to insert */
bulk.RecordCount = 100;  /* We have 100 dates to insert */

/* Fill bulk.Records[i] with date data ... */
for (DWORD i = 0; i < bulk.RecordCount; i++) {
    /* Populate bulk.Records[i] */
}

/* Insert all records in a single operation */
HRESULT hr = InsertDateLogHandleToOdbcDatabase(
    hDateLog,
    &bulk      /* Bulk data to insert */
);

if (SUCCEEDED(hr)) {
    printf("Successfully inserted %lu date records\n", bulk.RecordCount);
}

Sample Code

Complete Example: Bulk Fetching Dates from SQL Server


#include "datelog.h"
#include 
#include 
#include 

int main(void)
{
    HRESULT hr = S_OK;
    DATE_LOG_HANDLE hDateLog = NULL;
    ODBC_CONNECT_PARAMS *pParams = NULL;
    SQL_DATE_BULK bulk = {0};
    DWORD totalRecordsFetched = 0;

    /* Step 1: Initialize connection parameters */
    hr = InitializeOdbcConnectParams(&pParams);
    if (FAILED(hr)) {
        printf("Failed to initialize ODBC parameters.\n");
        return 1;
    }

    /* Step 2: Configure connection string */
    if (pParams->AddParam != NULL) {
        pParams->AddParam(pParams, "Driver", "{ODBC Driver 17 for SQL Server}");
        pParams->AddParam(pParams, "Server", "localhost\\SQLEXPRESS");
        pParams->AddParam(pParams, "Database", "DateDatabase");
        pParams->AddParam(pParams, "Trusted_Connection", "yes");
    }

    /* Step 3: Initialize date log handle */
    hr = InitializeDateLogHandle(
        NULL, DATE_LOG_MAX, NULL, &hDateLog, HandleIsForDatelog
    );
    if (FAILED(hr)) {
        printf("Failed to initialize date log handle.\n");
        FreeOdbcConnectParams(&pParams);
        return 1;
    }

    /* Step 4: Connect to database */
    hr = ConnectDateLogHandleToOdbcDatabase(
        hDateLog,
        pParams,
        DATE_LOG_ODBC_LEVEL_READ_ONLY
    );
    if (FAILED(hr)) {
        printf("Failed to connect to database with HRESULT 0x%08lx.\n", hr);
        CloseDateLogHandle(hDateLog);
        FreeOdbcConnectParams(&pParams);
        return 1;
    }

    printf("Connected to database successfully.\n");

    /* Step 5: Fetch dates in bulk */
    printf("\nFetching date records in bulk...\n");
    
    while (1) {
        /* Reset bulk structure for next fetch */
        ZeroMemory(&bulk, sizeof(SQL_DATE_BULK));
        
        /* Fetch up to 1000 records */
        hr = FetchDateLogHandleToOdbcDatabase(
            hDateLog,
            &bulk,
            1000
        );
        
        if (FAILED(hr)) {
            printf("Bulk fetch failed with HRESULT 0x%08lx.\n", hr);
            break;
        }
        
        if (bulk.RecordCount == 0) {
            printf("No more records to fetch.\n");
            break;
        }
        
        printf("Fetched %lu records (Total: %lu)\n", 
            bulk.RecordCount, 
            totalRecordsFetched + bulk.RecordCount);
        
        /* Process fetched records */
        for (DWORD i = 0; i < bulk.RecordCount; i++) {
            if (bulk.RowStatusArray != NULL) {
                SQLLEN status = bulk.RowStatusArray[i];
                
                if (status == SQL_ROW_SUCCESS) {
                    /* Process successful record */
                    /* printf("  Record %lu: Success\n", i); */
                } else if (status == SQL_ROW_DELETED) {
                    printf("  Record %lu: Deleted\n", i);
                } else {
                    printf("  Record %lu: Status %ld\n", i, status);
                }
            }
        }
        
        totalRecordsFetched += bulk.RecordCount;
        
        /* If fewer than requested records were returned, we've reached the end */
        if (bulk.RecordCount < 1000) {
            break;
        }
    }

    printf("\n=== Summary ===\n");
    printf("Total records fetched: %lu\n", totalRecordsFetched);
    printf("Last operation status: 0x%08lx\n", bulk.LastOperationStatus);

    /* Step 6: Cleanup */
    if (hDateLog != NULL) {
        CloseDateLogHandle(hDateLog);
    }
    
    if (pParams != NULL) {
        FreeOdbcConnectParams(&pParams);
    }

    printf("\nCleanup completed successfully.\n");
    return 0;
}