You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
746 lines
27 KiB
746 lines
27 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
|
//
|
|
// File: oledbutl.cpp
|
|
//
|
|
// Contents:
|
|
//
|
|
//
|
|
// History: 07/10/96 RenatoB Created, lifted from EricJ code
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// Includes
|
|
#include "oleds.hxx"
|
|
|
|
// All the '256's below should be 4 (the length of a pointer to a string). Because
|
|
// of a bug in the TempTable, this has been temporarily done.
|
|
//
|
|
// Note: Provider-specific types are returned as octet strings
|
|
//
|
|
MAPTYPE_STRUCT g_MapADsTypeToDBType[] = {
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_INVALID = 0, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_DN_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_CASE_EXACT_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_CASE_IGNORE_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_PRINTABLE_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_NUMERIC_STRING, */
|
|
{DBTYPE_BOOL, 2}, /* ADSTYPE_BOOLEAN, */
|
|
{DBTYPE_I4, 4}, /* ADSTYPE_INTEGER, */
|
|
{DBTYPE_BYTES | DBTYPE_BYREF, 256}, /* ADSTYPE_OCTET_STRING, */
|
|
{DBTYPE_DATE, 8}, /* ADSTYPE_UTC_TIME, */
|
|
{DBTYPE_VARIANT |DBTYPE_BYREF,16}, /* ADSTYPE_LARGE_INTEGER, */
|
|
{DBTYPE_BYTES | DBTYPE_BYREF, 256}, /* ADSTYPE_PROV_SPECIFIC */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_OBJECT_CLASS, */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_CASEIGNORE_LIST */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_OCTET_LIST */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_PATH */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_POSTALADDRESS */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_TIMESTAMP */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_BACKLINK */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_TYPEDNAME */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_HOLD */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_NETADDRESS */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_REPLICAPOINTER */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_FAXNUMBER */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_EMAIL */
|
|
{DBTYPE_BYTES | DBTYPE_BYREF, 256}, /* ADSTYPE_NT_SECURITY_DESC */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_UNKNOWN */
|
|
{DBTYPE_VARIANT |DBTYPE_BYREF,16}, /* ADSTYPE_DN_WITH_BINARY */
|
|
{DBTYPE_VARIANT |DBTYPE_BYREF,16} /* ADSTYPE_DN_WITH_STRING */
|
|
};
|
|
|
|
DWORD g_cMapADsTypeToDBType = (sizeof(g_MapADsTypeToDBType) /
|
|
sizeof(g_MapADsTypeToDBType[0]));
|
|
|
|
// The row object does not use IDirectorySearch when a direct bind or SELECT
|
|
// * happens. In this case, it uses IADs::Get. It is possible that a variant
|
|
// with VT_DISPATCH may be returned in this case - for ADSTYPE_NT_SECURITY_DESC
|
|
// DNWithBin or DNWithStr. In this case, they cannot be converted to any other
|
|
// DBTYPE. So, they will be returned as DBTYPE_VARIANT.
|
|
MAPTYPE_STRUCT g_MapADsTypeToDBType2[] = {
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_INVALID = 0, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_DN_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_CASE_EXACT_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_CASE_IGNORE_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_PRINTABLE_STRING, */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_NUMERIC_STRING, */
|
|
{DBTYPE_BOOL, 2}, /* ADSTYPE_BOOLEAN, */
|
|
{DBTYPE_I4, 4}, /* ADSTYPE_INTEGER, */
|
|
{DBTYPE_BYTES | DBTYPE_BYREF, 256}, /* ADSTYPE_OCTET_STRING, */
|
|
{DBTYPE_DATE, 8}, /* ADSTYPE_UTC_TIME, */
|
|
{DBTYPE_VARIANT, 16}, /* ADSTYPE_LARGE_INTEGER, */
|
|
{DBTYPE_BYTES | DBTYPE_BYREF, 256}, /* ADSTYPE_PROV_SPECIFIC */
|
|
{DBTYPE_WSTR | DBTYPE_BYREF, 256}, /* ADSTYPE_OBJECT_CLASS, */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_CASEIGNORE_LIST */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_OCTET_LIST */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_PATH */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_POSTALADDRESS */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_TIMESTAMP */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_BACKLINK */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_TYPEDNAME */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_HOLD */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_NETADDRESS */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_REPLICAPOINTER */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_FAXNUMBER */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_EMAIL */
|
|
{DBTYPE_BYTES | DBTYPE_BYREF, 256}, /* ADSTYPE_NT_SECURITY_DESC */
|
|
{DBTYPE_NULL, 0}, /* ADSTYPE_UNKNOWN */
|
|
{DBTYPE_VARIANT, 16}, /* ADSTYPE_DN_WITH_BINARY */
|
|
{DBTYPE_VARIANT, 16} /* ADSTYPE_DN_WITH_STRING */
|
|
};
|
|
|
|
DWORD g_cMapADsTypeToDBType2 = (sizeof(g_MapADsTypeToDBType2) /
|
|
sizeof(g_MapADsTypeToDBType2[0]));
|
|
|
|
VARTYPE g_MapADsTypeToVarType[] = {
|
|
VT_NULL, /* ADSTYPE_INVALID = 0, */
|
|
VT_BSTR, /* ADSTYPE_DN_STRING, */
|
|
VT_BSTR, /* ADSTYPE_CASE_EXACT_STRING, */
|
|
VT_BSTR, /* ADSTYPE_CASE_IGNORE_STRING, */
|
|
VT_BSTR, /* ADSTYPE_PRINTABLE_STRING, */
|
|
VT_BSTR, /* ADSTYPE_NUMERIC_STRING, */
|
|
VT_BOOL, /* ADSTYPE_BOOLEAN, */
|
|
VT_I4, /* ADSTYPE_INTEGER, */
|
|
VT_UI1 | VT_ARRAY, /* ADSTYPE_OCTET_STRING, */
|
|
VT_DATE, /* ADSTYPE_UTC_TIME, */
|
|
VT_DISPATCH, /* ADSTYPE_LARGE_INTEGER, */
|
|
VT_UI1 | VT_ARRAY, /* ADSTYPE_PROV_SPECIFIC */
|
|
VT_BSTR, /* ADSTYPE_OBJECT_CLASS */
|
|
VT_NULL, /* ADSTYPE_CASEIGNORE_LIST */
|
|
VT_NULL, /* ADSTYPE_OCTET_LIST */
|
|
VT_NULL, /* ADSTYPE_PATH */
|
|
VT_NULL, /* ADSTYPE_POSTALADDRESS */
|
|
VT_NULL, /* ADSTYPE_TIMESTAMP */
|
|
VT_NULL, /* ADSTYPE_BACKLINK */
|
|
VT_NULL, /* ADSTYPE_TYPEDNAME */
|
|
VT_NULL, /* ADSTYPE_HOLD */
|
|
VT_NULL, /* ADSTYPE_NETADDRESS */
|
|
VT_NULL, /* ADSTYPE_REPLICAPOINTER */
|
|
VT_NULL, /* ADSTYPE_FAXNUMBER */
|
|
VT_NULL, /* ADSTYPE_EMAIL */
|
|
VT_UI1 | VT_ARRAY, /* ADSTYPE_NT_SECURITY_DESC */
|
|
VT_NULL, /* ADSTYPE_UNKNOWN */
|
|
VT_DISPATCH, /* ADSTYPE_DN_WITH_BINARY */
|
|
VT_DISPATCH /* ADSTYPE_DN_WITH_STRING */
|
|
};
|
|
|
|
DWORD g_cMapADsTypeToVarType = (sizeof(g_MapADsTypeToVarType) /
|
|
sizeof(g_MapADsTypeToVarType[0]));
|
|
|
|
|
|
ADS_SEARCHPREF g_MapDBPropIdToSearchPref[] = {
|
|
ADS_SEARCHPREF_ASYNCHRONOUS,
|
|
ADS_SEARCHPREF_DEREF_ALIASES,
|
|
ADS_SEARCHPREF_SIZE_LIMIT,
|
|
ADS_SEARCHPREF_TIME_LIMIT,
|
|
ADS_SEARCHPREF_ATTRIBTYPES_ONLY,
|
|
ADS_SEARCHPREF_SEARCH_SCOPE,
|
|
ADS_SEARCHPREF_TIMEOUT,
|
|
ADS_SEARCHPREF_PAGESIZE,
|
|
ADS_SEARCHPREF_PAGED_TIME_LIMIT,
|
|
ADS_SEARCHPREF_CHASE_REFERRALS,
|
|
ADS_SEARCHPREF_SORT_ON,
|
|
ADS_SEARCHPREF_CACHE_RESULTS
|
|
};
|
|
|
|
DWORD g_cMapDBPropToSearchPref = (sizeof(g_MapDBPropIdToSearchPref) /
|
|
sizeof(g_MapDBPropIdToSearchPref[0]));
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CpAccessors2Rowset
|
|
//
|
|
// Synopsis: @ffunc Implements inheritance of Accessors. Copies to
|
|
// a Rowset the accessors existing on the command
|
|
//
|
|
// Called by: CRowset::Finit
|
|
// Called when: At runtime.
|
|
// Overridden: No. (Private)
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Returns: @rdesc HRESULT
|
|
// @flag S_OK | OK
|
|
// @flag E_OUTOFMEMORY |could not get IMalloc
|
|
// @flag E_FAIL| An accessor could not be created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CpAccessors2Rowset(
|
|
IAccessor *pAccessorCommand, //@parm IN |Command's IAccessor
|
|
IAccessor *pAccessorRowset, //@parm IN |Rowset's IAccessor
|
|
ULONG cAccessors, //@parm IN |Count,Commnands accessors
|
|
HACCESSOR rgAccessors[], //@parm IN |Array,Command's accessors
|
|
CImpIAccessor *pCAccessor //accessor object of rowset
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IMalloc * pMalloc = NULL;
|
|
DBCOUNTITEM cBindings;
|
|
DBBINDING * pBindings = NULL;
|
|
DBBINDSTATUS * prgBindStatus = NULL;
|
|
ULONG i,j;
|
|
DBACCESSORFLAGS AccessorFlags;
|
|
HACCESSOR hAccessor;
|
|
|
|
hr = CoGetMalloc(MEMCTX_TASK, &pMalloc);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//for each of the command's accessors,
|
|
// we create a Rowset accessor.
|
|
// if anyone fails, return E_FAIL
|
|
|
|
for (i=0; i<cAccessors; i++) {
|
|
AccessorFlags = 0;
|
|
hr=pAccessorCommand->GetBindings(
|
|
rgAccessors[i],
|
|
&AccessorFlags,
|
|
&cBindings,
|
|
&pBindings
|
|
);
|
|
|
|
// Not a valid accessor handle
|
|
if (hr == DB_E_BADACCESSORHANDLE) {
|
|
// Rowset will also inherit the bad accessor
|
|
hr = pCAccessor->CreateBadAccessor();
|
|
BAIL_ON_FAILURE( hr );
|
|
|
|
continue;
|
|
}
|
|
BAIL_ON_FAILURE( hr );
|
|
|
|
// Allocate memory for the Status values
|
|
prgBindStatus = (DBBINDSTATUS*) pMalloc->Alloc((ULONG)(cBindings *
|
|
sizeof(DBBINDSTATUS)));
|
|
|
|
if (NULL == prgBindStatus)
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
|
|
hr=pAccessorRowset->CreateAccessor(
|
|
AccessorFlags,
|
|
cBindings,
|
|
pBindings,
|
|
0,
|
|
&hAccessor,
|
|
prgBindStatus
|
|
);
|
|
|
|
//
|
|
// If CreateAccessor fails fixup DB_E_ERRORSOCCURRED
|
|
//
|
|
if (hr == DB_E_ERRORSOCCURRED) {
|
|
// Fixup the HResult
|
|
for(j=0; j < cBindings; j++) {
|
|
switch (prgBindStatus[j])
|
|
{
|
|
case DBBINDSTATUS_NOINTERFACE:
|
|
BAIL_ON_FAILURE( hr=E_NOINTERFACE );
|
|
|
|
case DBBINDSTATUS_BADBINDINFO:
|
|
BAIL_ON_FAILURE( hr=DB_E_BADBINDINFO );
|
|
|
|
case DBBINDSTATUS_BADORDINAL:
|
|
BAIL_ON_FAILURE( hr=DB_E_BADORDINAL );
|
|
|
|
case DBBINDSTATUS_BADSTORAGEFLAGS:
|
|
BAIL_ON_FAILURE( hr=DB_E_BADSTORAGEFLAGS );
|
|
|
|
case DBBINDSTATUS_UNSUPPORTEDCONVERSION:
|
|
BAIL_ON_FAILURE( hr=DB_E_UNSUPPORTEDCONVERSION );
|
|
|
|
case DBBINDSTATUS_MULTIPLESTORAGE:
|
|
BAIL_ON_FAILURE( hr=DB_E_MULTIPLESTORAGE );
|
|
|
|
case DBBINDSTATUS_OK:
|
|
default:
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
// Should never be E_FAIL
|
|
ADsAssert(hr != E_FAIL);
|
|
}
|
|
BAIL_ON_FAILURE( hr );
|
|
|
|
if( pBindings )
|
|
pMalloc->Free(pBindings);
|
|
pBindings = NULL;
|
|
|
|
if( prgBindStatus )
|
|
pMalloc->Free(prgBindStatus);
|
|
prgBindStatus = NULL;
|
|
};
|
|
|
|
error:
|
|
|
|
if (pMalloc)
|
|
{
|
|
if( pBindings )
|
|
pMalloc->Free(pBindings);
|
|
if( prgBindStatus )
|
|
pMalloc->Free(prgBindStatus);
|
|
pMalloc->Release();
|
|
}
|
|
|
|
RRETURN( hr );
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetDSInterface(
|
|
LPWSTR lpszPath,
|
|
CCredentials& Credentials,
|
|
REFIID iid,
|
|
void FAR * FAR * ppObject
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPWSTR lpszUserName=NULL, lpszPassword=NULL;
|
|
DWORD dwAuthFlags = 0;
|
|
|
|
hr = Credentials.GetUserName(&lpszUserName);
|
|
BAIL_ON_FAILURE( hr );
|
|
|
|
hr = Credentials.GetPassword(&lpszPassword);
|
|
BAIL_ON_FAILURE( hr );
|
|
|
|
dwAuthFlags = Credentials.GetAuthFlags();
|
|
|
|
hr = ADsOpenObject(
|
|
lpszPath,
|
|
lpszUserName,
|
|
lpszPassword,
|
|
dwAuthFlags,
|
|
iid,
|
|
ppObject
|
|
);
|
|
|
|
if( INVALID_CREDENTIALS_ERROR(hr) )
|
|
BAIL_ON_FAILURE( hr=DB_SEC_E_PERMISSIONDENIED );
|
|
|
|
if( FAILED(hr) )
|
|
BAIL_ON_FAILURE( hr=DB_E_NOTABLE );
|
|
|
|
error:
|
|
|
|
if( lpszUserName )
|
|
FreeADsMem(lpszUserName);
|
|
|
|
if( lpszPassword )
|
|
{
|
|
SecureZeroMemory(lpszPassword, wcslen(lpszPassword) * sizeof(WCHAR));
|
|
FreeADsMem(lpszPassword);
|
|
}
|
|
|
|
RRETURN( hr );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetCredentialsFromIAuthenticate
|
|
//
|
|
// Synopsis: Gets credentials (user name, password) from IAuthenticate
|
|
// interface pointer.
|
|
//
|
|
// Returns: HRESULT
|
|
//----------------------------------------------------------------------------
|
|
HRESULT GetCredentialsFromIAuthenticate(
|
|
IAuthenticate *pAuthenticate,
|
|
CCredentials& refCredentials
|
|
)
|
|
{
|
|
Assert(pAuthenticate);
|
|
|
|
HRESULT hr = S_OK;
|
|
HWND hwnd;
|
|
PWSTR pszUsername = NULL;
|
|
PWSTR pszPassword = NULL;
|
|
|
|
if (pAuthenticate->Authenticate(&hwnd, &pszUsername, &pszPassword) != S_OK)
|
|
RRETURN(E_INVALIDARG);
|
|
|
|
if ((hwnd != INVALID_HANDLE_VALUE) &&
|
|
(hwnd != 0))
|
|
{
|
|
//don't know if and how to handle this case
|
|
RRETURN(S_OK);
|
|
}
|
|
else
|
|
{
|
|
hr = refCredentials.SetUserName(pszUsername);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = refCredentials.SetPassword(pszPassword);
|
|
}
|
|
|
|
if (pszPassword)
|
|
{
|
|
SecureZeroMemory(pszPassword, wcslen(pszPassword) * sizeof(WCHAR));
|
|
CoTaskMemFree(pszPassword);
|
|
}
|
|
if (pszUsername)
|
|
{
|
|
CoTaskMemFree(pszUsername);
|
|
}
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: RemoveWhiteSpaces
|
|
//
|
|
// Synopsis: Removes the leading and trailing white spaces
|
|
//
|
|
// Arguments: pszText Text strings from which the leading
|
|
// and trailing white spaces are to be
|
|
// removed
|
|
//
|
|
// Returns: LPWSTR Pointer to the modified string
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 08-15-96 ShankSh Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
LPWSTR
|
|
RemoveWhiteSpaces(LPWSTR pszText)
|
|
{
|
|
LPWSTR pChar;
|
|
|
|
if( !pszText )
|
|
return( pszText );
|
|
|
|
while(*pszText && iswspace(*pszText))
|
|
pszText++;
|
|
|
|
for(pChar = pszText + wcslen(pszText) - 1; pChar >= pszText; pChar--) {
|
|
if( !iswspace(*pChar) )
|
|
break;
|
|
else
|
|
*pChar = L'\0';
|
|
}
|
|
|
|
return pszText;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CanConvertHelper
|
|
//
|
|
// Synopsis: Helper that tells the consumer if the conversion is supported.
|
|
//
|
|
// Arguments: DBTYPE wSrcType
|
|
// DBTYPE wDstType
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 08-15-96 ShankSh Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Bitmask of supported conversions --
|
|
// - src type is index into array,
|
|
// - dst type is bit in that ULONG
|
|
//
|
|
static ULONG s_rgConvertBitmap[] =
|
|
{
|
|
// 3 2 2 2 2 2 1 1 1 1 1 0 0 0 0 0.
|
|
// 0 8 6 4 2 0 8 6 4 2 0 8 6 4 2 0.
|
|
// 3 2 2 2 2 2 1 1 1 1 1 0 0 0 0 0.
|
|
// 1 9 7 5 3 1 9 7 5 3 1 9 7 5 3 1.
|
|
// DBTYPE_EMPTY
|
|
0xe3bfd9ff, // 11100011101111111101100111111111
|
|
// DBTYPE_NULL
|
|
0x60001002, // 01100000000000000001000000000010
|
|
// DBTYPE_I2
|
|
0xdf9fd9ff, // 11011111100111111101100111111111
|
|
// DBTYPE_I4
|
|
0xdfdfd9ff, // 11011111110111111101100111111111
|
|
// DBTYPE_R4
|
|
0xdf9fd9ff, // 11011111100111111101100111111111
|
|
// DBTYPE_R8
|
|
0xdf9fd9ff, // 11011111100111111101100111111111
|
|
// DBTYPE_CY
|
|
0xc39fd97f, // 11000011100111111101100101111111
|
|
// DBTYPE_DATE
|
|
0x7d9f99bf, // 01111101100111111001100110111111
|
|
// DBTYPE_BSTR
|
|
0xffffd9ff, // 11111111111111111101100111111111
|
|
// DBTYPE_IDISPATCH
|
|
0x4087fbff, // 01000000100001111111101111111111
|
|
// DBTYPE_ERROR
|
|
0x01001500, // 00000001000000000001010100000000
|
|
// DBTYPE_BOOL
|
|
0xc39fd9ff, // 11000011100111111101100111111111
|
|
// DBTYPE_VARIANT
|
|
0xffffffff, // 11111111111111111111111111111111
|
|
// DBTYPE_IUNKNOWN
|
|
0x00003203, // 00000000000000000011001000000011
|
|
// DBTYPE_DECIMAL
|
|
0x9f9fd97f, // 10011111100111111101100101111111
|
|
// DBTYPE_I1
|
|
0x9f9fd9ff, // 10011111100111111101100111111111
|
|
// DBTYPE_UI1
|
|
0xdf9fd9ff, // 11011111100111111101100111111111
|
|
// DBTYPE_UI2
|
|
0xdf9fd9ff, // 11011111100111111101100111111111
|
|
// DBTYPE_UI4
|
|
0xdfdfd9ff, // 11011111110111111101100111111111
|
|
// DBTYPE_I8
|
|
0x619fd13f, // 01100001100111111101000100111111
|
|
// DBTYPE_UI8
|
|
0x619fd13f, // 01100001100111111101000100111111
|
|
// DBTYPE_GUID
|
|
0x41a01103, // 01000001101000000001000100000011
|
|
// DBTYPE_BYTES
|
|
0x41c4110b, // 01000001110001000001000100001011
|
|
// DBTYPE_STR
|
|
0xffffd9ff, // 11111111111111111101100111111111
|
|
// DBTYPE_WSTR
|
|
0xffffd9ff, // 11111111111111111101100111111111
|
|
// DBTYPE_NUMERIC
|
|
0xc39fd97f, // 11000011100111111101100101111111
|
|
// DBTYPE_DBDATE
|
|
0x3d801183, // 00111101100000000001000110000011
|
|
// DBTYPE_DBTIME
|
|
0x3d801183, // 00111101100000000001000110000011
|
|
// DBTYPE_DBTIMESTAMP
|
|
0x3d801183, // 00111101100000000001000110000011
|
|
// DBTYPE_FILETIME
|
|
0x7d981183, // 01111101100110000001000110000011
|
|
// DBTYPE_PROPVARIANT
|
|
0xffffffff, // 11111111111111111111111111111111
|
|
// DBTYPE_VARNUMERIC
|
|
0x839fd97f, // 10000011100111111101100101111111
|
|
};
|
|
|
|
static HRESULT IsLegalDBtype(DBTYPE);
|
|
static LONG IndexDBTYPE(DBTYPE wType);
|
|
|
|
STDMETHODIMP
|
|
CanConvertHelper(
|
|
DBTYPE wSrcType,
|
|
DBTYPE wDstType,
|
|
DBCONVERTFLAGS dwConvertFlags
|
|
)
|
|
{
|
|
//
|
|
// Check in-params and NULL out-params in case of error
|
|
//
|
|
if( (dwConvertFlags &
|
|
~(DBCONVERTFLAGS_ISLONG |
|
|
DBCONVERTFLAGS_ISFIXEDLENGTH |
|
|
DBCONVERTFLAGS_FROMVARIANT)) != DBCONVERTFLAGS_COLUMN )
|
|
RRETURN( DB_E_BADCONVERTFLAG );
|
|
|
|
//
|
|
// Make sure that we check that the type is a variant if they say so
|
|
//
|
|
if( dwConvertFlags & DBCONVERTFLAGS_FROMVARIANT ) {
|
|
DBTYPE wVtType = wSrcType & VT_TYPEMASK;
|
|
|
|
// Take out all of the Valid VT_TYPES (36 is VT_RECORD in VC 6)
|
|
if( (wVtType > VT_DECIMAL && wVtType < VT_I1) ||
|
|
((wVtType > VT_LPWSTR && wVtType < VT_FILETIME) && wVtType !=36) ||
|
|
(wVtType > VT_CLSID) )
|
|
RRETURN( DB_E_BADTYPE );
|
|
}
|
|
|
|
//
|
|
// Don't allow _ISLONG on fixed-length types
|
|
//
|
|
if( dwConvertFlags & DBCONVERTFLAGS_ISLONG ) {
|
|
switch ( wSrcType & ~(DBTYPE_RESERVED|DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_BYREF) )
|
|
{
|
|
case DBTYPE_BYTES:
|
|
case DBTYPE_STR:
|
|
case DBTYPE_WSTR:
|
|
case DBTYPE_VARNUMERIC:
|
|
break;
|
|
|
|
default:
|
|
RRETURN( DB_E_BADCONVERTFLAG );
|
|
}
|
|
}
|
|
|
|
// Check for valid types
|
|
if( wSrcType > DBTYPE_DECIMAL )
|
|
{
|
|
if( FAILED(IsLegalDBtype(wSrcType)) )
|
|
RRETURN( S_FALSE );
|
|
}
|
|
if( wDstType > DBTYPE_DECIMAL )
|
|
{
|
|
if( FAILED(IsLegalDBtype(wDstType)) )
|
|
RRETURN( S_FALSE );
|
|
}
|
|
|
|
// Check for unsupported type modifiers
|
|
if( (wSrcType & (DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_RESERVED)) ||
|
|
(wDstType & (DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_RESERVED)) )
|
|
RRETURN( S_FALSE );
|
|
|
|
// Handle BYREF destination separately
|
|
if( wDstType & DBTYPE_BYREF ) {
|
|
// Turn off BYREF bit
|
|
wDstType &= ~DBTYPE_BYREF;
|
|
|
|
// We only allow BYREF destination for variable length types
|
|
switch ( wDstType ) {
|
|
case DBTYPE_BYTES:
|
|
case DBTYPE_STR:
|
|
case DBTYPE_WSTR:
|
|
case DBTYPE_VARNUMERIC:
|
|
break;
|
|
|
|
default:
|
|
// Fixed-length BYREFs are not supported
|
|
RRETURN( S_FALSE );
|
|
}
|
|
}
|
|
|
|
// Turn off BYREF bit
|
|
wSrcType &= ~DBTYPE_BYREF;
|
|
|
|
// Get the indices for the src and dst types
|
|
LONG iSrc = IndexDBTYPE(wSrcType);
|
|
ADsAssert(iSrc < NUMELEM(s_rgConvertBitmap)); // better not be larger than our array
|
|
|
|
LONG iDst = IndexDBTYPE(wDstType);
|
|
ADsAssert(iDst < (sizeof(ULONG) * 8) ); // or the number of bits in a ULONG
|
|
|
|
// Make sure we have two supported types -- we don't support UDT
|
|
if( iSrc < 0 || iDst < 0 )
|
|
RRETURN( S_FALSE );
|
|
|
|
// And do the lookup -- bit will be set if conversion supported
|
|
if( s_rgConvertBitmap[iSrc] & (1 << iDst) )
|
|
RRETURN( S_OK );
|
|
|
|
// No bit, no support
|
|
RRETURN( S_FALSE );
|
|
}
|
|
|
|
|
|
HRESULT IsLegalDBtype(DBTYPE dbtype)
|
|
{
|
|
// NOTE: optimized for speed, rather than for maintainablity
|
|
if( dbtype & (DBTYPE_VECTOR|DBTYPE_BYREF|DBTYPE_ARRAY|DBTYPE_RESERVED) )
|
|
dbtype &= ~(DBTYPE_VECTOR|DBTYPE_BYREF|DBTYPE_ARRAY|DBTYPE_RESERVED);
|
|
|
|
if( (dbtype >= DBTYPE_EMPTY && dbtype <= DBTYPE_DECIMAL) ||
|
|
(dbtype >= DBTYPE_I1 && dbtype <= DBTYPE_UI8) ||
|
|
dbtype == DBTYPE_GUID ||
|
|
(dbtype >= DBTYPE_BYTES && dbtype <= DBTYPE_DBTIMESTAMP) ||
|
|
(dbtype >= DBTYPE_FILETIME && dbtype <= DBTYPE_VARNUMERIC) )
|
|
RRETURN( S_OK );
|
|
|
|
RRETURN( DB_E_BADBINDINFO );
|
|
}
|
|
|
|
|
|
LONG IndexDBTYPE(DBTYPE wType)
|
|
{
|
|
switch ( wType ) {
|
|
case DBTYPE_EMPTY: // 0
|
|
case DBTYPE_NULL: // 1
|
|
case DBTYPE_I2: // 2
|
|
case DBTYPE_I4: // 3
|
|
case DBTYPE_R4: // 4
|
|
case DBTYPE_R8: // 5
|
|
case DBTYPE_CY: // 6
|
|
case DBTYPE_DATE: // 7
|
|
case DBTYPE_BSTR: // 8
|
|
case DBTYPE_IDISPATCH: // 9
|
|
case DBTYPE_ERROR: // 10
|
|
case DBTYPE_BOOL: // 11
|
|
case DBTYPE_VARIANT: // 12
|
|
case DBTYPE_IUNKNOWN: // 13
|
|
case DBTYPE_DECIMAL: // 14
|
|
// 0 - 14
|
|
return (ULONG)wType;
|
|
|
|
case DBTYPE_I1: // 16
|
|
case DBTYPE_UI1: // 17
|
|
case DBTYPE_UI2: // 18
|
|
case DBTYPE_UI4: // 19
|
|
case DBTYPE_I8: // 20
|
|
case DBTYPE_UI8: // 21
|
|
// 15 - 20
|
|
return (ULONG)(wType - 1);
|
|
|
|
case DBTYPE_GUID: // 72
|
|
// 21
|
|
return 21;
|
|
|
|
case DBTYPE_BYTES: // 128
|
|
case DBTYPE_STR: // 129
|
|
case DBTYPE_WSTR: // 130
|
|
case DBTYPE_NUMERIC: // 131
|
|
// 22 - 25
|
|
return (ULONG)(wType - 106);
|
|
|
|
case DBTYPE_DBDATE: // 133
|
|
case DBTYPE_DBTIME: // 134
|
|
case DBTYPE_DBTIMESTAMP:// 135
|
|
// 26 - 28
|
|
return (ULONG)(wType - 107);
|
|
|
|
case DBTYPE_FILETIME: // 64
|
|
// 29
|
|
return wType - 35;
|
|
case DBTYPE_PROPVARIANT:// 138
|
|
case DBTYPE_VARNUMERIC: // 139
|
|
// 30 - 31
|
|
return (ULONG)(wType - 108);
|
|
}
|
|
|
|
// No match
|
|
return -1;
|
|
}
|
|
|
|
BYTE SetPrecision(DBTYPE dbType)
|
|
{
|
|
switch(dbType)
|
|
{
|
|
case DBTYPE_I1:
|
|
case DBTYPE_UI1:
|
|
return 3;
|
|
case DBTYPE_I2:
|
|
case DBTYPE_UI2:
|
|
return 5;
|
|
case DBTYPE_I4:
|
|
case DBTYPE_UI4:
|
|
return 10;
|
|
case DBTYPE_I8:
|
|
return 19;
|
|
case DBTYPE_UI8:
|
|
return 20;
|
|
case DBTYPE_R4:
|
|
return 7;
|
|
case DBTYPE_R8:
|
|
return 15;
|
|
case DBTYPE_CY:
|
|
return 19;
|
|
case DBTYPE_DECIMAL:
|
|
return 29;
|
|
case DBTYPE_NUMERIC:
|
|
return 39;
|
|
case DBTYPE_VARNUMERIC:
|
|
return 255;
|
|
default:
|
|
return ((BYTE) (~0));
|
|
}
|
|
}
|
|
|
|
|