Add an ODBC connection-string parameter to a DATE_LOG_HANDLE's connection slot
AddOdbcParamter validates and adds a single connection-string parameter (keyword/value pair,
tri-state flag, or protected credential) into the internal parameter list of the ODBC connection identified by
OdbcLevel on hDateLogHandle. It is the public, handle-based wrapper around OdbcAddParamImpl(),
resolving OdbcLevel to its PODBC_CONNECTION_CONTEXT via GetOdbcConnectionContextFromHandle()
under the handle’s lock. (The function name is spelled “Paramter” in the library; use that spelling exactly.)
This is the function that the public ODBC_CONNECT_PARAMS page describes as the target of the AddParam function pointer; however it may also be called directly against an
already-initialized ODBC connection slot on a DATE_LOG_HANDLE (see InitializeDateLogHandleOdbc).
HRESULT _Must_inspect_result_ _Success_(SUCCEEDED(return)) AddOdbcParamter(
_In_ DATE_LOG_HANDLE hDateLogHandle,
_In_ ODBC_PARAM_KEY eKey,
_In_opt_ LPVOID pvValue,
_In_ DWORD cbValue,
_In_ ODBC_PARAM_TYPE eType,
_In_ ODBC_TRISTATE eTriValue,
_In_ DWORD dwCredFlags,
_In_ DATE_LOG_ODBC_LEVEL OdbcLevel
);
[In] DATE_LOG_HANDLE
A valid DATE_LOG_HANDLE with ODBC connection internals already initialized (see InitializeDateLogHandleOdbc).
HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE))[In] ODBC_PARAM_KEY
The enumerator identifying the connection-string keyword (for example ODBC_KEY_SERVER or ODBC_KEY_DRIVER).
HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)[In, Optional] LPVOID
The value to encode.
ODBC_PARAM_TYPE_TRISTATE; required for every other type[In] DWORD
Size in bytes of pvValue (string/raw/protected-credential types).
ODBC_PARAM_TYPE_TRISTATE, which carries no value buffer[In] ODBC_PARAM_TYPE
How the value is interpreted.
ODBC_PARAM_TYPE_STRING — text valueODBC_PARAM_TYPE_RAW — raw bytesODBC_PARAM_TYPE_TRISTATE — flag taken from eTriValue; pvValue may be NULLODBC_PARAM_TYPE_PROTECTED_CREDENTIAL — protected credential; dwCredFlags applies[In] ODBC_TRISTATE
ODBC_YES, ODBC_NO, or ODBC_UNSPECIFIED; meaningful only for ODBC_PARAM_TYPE_TRISTATE.
ODBC_UNSPECIFIED for all other types[In] DWORD
CRED_PACK_* flags originally passed to CredPackAuthenticationBufferW(); meaningful only for ODBC_PARAM_TYPE_PROTECTED_CREDENTIAL.
0 for all other types[In] DATE_LOG_ODBC_LEVEL
DATE_LOG_ODBC_1 through DATE_LOG_ODBC_4, identifying which of up to four connection slots to target (DATE_LOG_MAX_ODBC_CONNECTIONS).
Parameter added successfully.
| Error | Cause |
|---|---|
| HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) | hDateLogHandle is NULL. |
| HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) | Key/type combination invalid (IsOdbcParamSetOk() failed), or pvValue is NULL for a non-tristate type. |
| HRESULT_FROM_WIN32(ERROR_INVALID_FLAGS) | OdbcLevel is 0, exceeds DATE_LOG_MAX_ODBC_CONNECTIONS, or no connection exists yet at that level. |
| HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE_STATE) | The handle’s ODBC connection internals have not been initialized. |
| HRESULT_FROM_WIN32(ERROR_UNIDENTIFIED_ERROR) | No connections have been registered on this handle yet (lParamCount == 0). |
Always test the result with FAILED()/SUCCEEDED(); the function is marked _Must_inspect_result_.
Validates the key/type/tri-state/cred-flags combination via IsOdbcParamSetOk(), resolves the
target connection context for OdbcLevel, and delegates the actual SLIST insertion (including singleton-key
replacement semantics for keys such as SERVER/DRIVER/DSN/UID/PWD) to OdbcAddParamImpl(). The entire
operation is performed under the DATE_LOG_HANDLE’s validated lock.
The operation runs under the handle’s validated lock, so concurrent calls on one handle are serialized. Duplicates created with DuplicateDateLogHandle share the same connections and therefore the same parameter lists.
The parameter is stored on the connection at OdbcLevel; the connection’s parameter list is released together with the connection when the last handle referencing the context is closed via CloseDateLogHandle. Your value buffer is not retained.
AddParam function pointer with a different signature (HRESULT (*)(pParams, LPCSTR pszKey, LPCSTR pszValue)) and tri-state values ODBC_TRUE/ODBC_FALSE, whereas this page documents ODBC_YES/ODBC_NO/ODBC_UNSPECIFIED.ODBC_PARAM_KEY values; only ODBC_KEY_SERVER and ODBC_KEY_DRIVER are named in the documentation.The example creates a date log, reserves ODBC slot 1, adds the driver and server (replacing the server once to show singleton-key behavior), and closes all handles on every path.
#include <stdio.h>
#include <wchar.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;
}
int main(void)
{
HOLIDAYS_HANDLE hHolidays = NULL;
DATE_LOG_HANDLE hDateLog = NULL;
HRESULT hr = E_FAIL;
int rc = 1;
/* Value strings. cbValue is a size in bytes; see Remarks for encoding notes. */
static const WCHAR szDriver[] = L"{ODBC Driver 17 for SQL Server}";
static const WCHAR szServer[] = L"localhost\\SQLEXPRESS";
/* 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;
}
/* The connection slot must be reserved before parameters can be added to it. */
hr = InitializeDateLogHandleOdbc(hDateLog, DATE_LOG_ODBC_1);
if (FAILED(hr)) {
printf("InitializeDateLogHandleOdbc failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
hr = AddOdbcParamter(hDateLog, ODBC_KEY_DRIVER, (LPVOID)szDriver,
(DWORD)(wcslen(szDriver) * sizeof(WCHAR)),
ODBC_PARAM_TYPE_STRING, ODBC_UNSPECIFIED, 0, DATE_LOG_ODBC_1);
if (FAILED(hr)) {
printf("Adding the driver failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
hr = AddOdbcParamter(hDateLog, ODBC_KEY_SERVER, (LPVOID)szServer,
(DWORD)(wcslen(szServer) * sizeof(WCHAR)),
ODBC_PARAM_TYPE_STRING, ODBC_UNSPECIFIED, 0, DATE_LOG_ODBC_1);
if (FAILED(hr)) {
printf("Adding the server failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
/* Server is a singleton key: adding it again replaces the earlier value. */
hr = AddOdbcParamter(hDateLog, ODBC_KEY_SERVER, (LPVOID)L"dbhost",
(DWORD)(wcslen(L"dbhost") * sizeof(WCHAR)),
ODBC_PARAM_TYPE_STRING, ODBC_UNSPECIFIED, 0, DATE_LOG_ODBC_1);
if (FAILED(hr)) {
printf("Replacing the server failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
printf("Connection parameters were added to ODBC level 1.\n");
rc = 0;
cleanup:
/* Closing the handle also releases the parameter list of its connections. */
if (hDateLog != NULL && FAILED(CloseDateLogHandle(hDateLog))) {
rc = 1;
}
if (FAILED(CloseDateLogHandle(hHolidays))) {
rc = 1;
}
return rc;
}