2025-04-27 07:49:33 -04:00

3752 lines
137 KiB
C++

//***************************************************************************
//
// (c) 1999-2001 by Microsoft Corp. All Rights Reserved.
//
// crepdrvr.cpp
//
// cvadai 19-Mar-99 Created as prototype for Quasar.
//
//***************************************************************************
#define _CREPDRVR_CPP_
#pragma warning( disable : 4786 ) // identifier was truncated to 'number' characters in the
#pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class
#define DBINITCONSTANTS // Initialize OLE constants...
#define INITGUID // ...once in each app.
#define _WIN32_DCOM
#include "precomp.h"
#include <std.h>
#include <sqlutils.h>
#include <repdrvr.h>
#include <crepdrvr.h>
#include <sqlexec.h>
#include <wbemint.h>
#include <math.h>
#include <objbase.h>
#include <resource.h>
#include <reputils.h>
#include <crc64.h>
#include <smrtptr.h>
#include <wqllex.h>
#include <wqlnode.h>
#include <wqlscan.h>
#include <genlex.h>
#include <opathlex.h>
//***************************************************************************
//
// HELPER FUNCTIONS for custom stuff
//
//***************************************************************************
void ClearPropArray (MappedProperties *pProps, DWORD dwNumProps)
{
int i = 0, j = 0;
for (i = 0; i < dwNumProps; i++)
{
delete pProps[i].wPropName;
delete pProps[i].wTableName;
delete pProps[i].wScopeClass;
for (j = 0; j < pProps[i].dwNumColumns; j++)
delete pProps[i].arrColumnNames[j];
for (j = 0; j < pProps[i].dwNumForeignKeys; j++)
delete pProps[i].arrForeignKeys[j];
delete pProps[i].arrColumnNames;
delete pProps[i].arrForeignKeys;
delete pProps[i].wClassTable;
delete pProps[i].wClassNameCol;
delete pProps[i].wClassDataCol;
delete pProps[i].wClassForeignKey;
}
}
HRESULT GetClassBufferID (CSQLConnection *pConn, MappedProperties *pProp,
LPWSTR lpTableName, LPWSTR lpClassName,
BYTE *pClassBuff, DWORD dwClassBuffLen, DWORD &dwClassID, IMalloc *pMalloc)
{
HRESULT hr = WBEM_S_NO_ERROR;
// Function to find an existing class buffer that matches this one
// byte for byte, or create a new row and get the new ID.
IRowset *pRowset = NULL;
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"select %s, %s from %s where %s = '%s'", &pRowset, NULL,
pProp->wClassForeignKey, pProp->wClassDataCol,
lpTableName, pProp->wClassNameCol, lpClassName);
if (SUCCEEDED(hr) && pRowset)
{
CReleaseMe r (pRowset);
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
BYTE *pBuffer = NULL;
DWORD dwLen = 0;
// Get each result row, and compare it with the passed in buffer
hr = CSQLExecute::GetColumnValue(pRowset, 1, pMalloc, &pRow, vTemp);
while (SUCCEEDED(hr))
{
hr = CSQLExecute::ReadImageValue(pRowset, 2, &pRow, &pBuffer, dwLen);
if (!memcmp(pClassBuff, pBuffer, dwLen))
{
dwClassID = vTemp.lVal;
}
hr = pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
pRow = NULL;
if (dwClassID)
break;
hr = CSQLExecute::GetColumnValue(pRowset, 1, pMalloc, &pRow, vTemp);
}
}
// If here, we didn't find one.
// Insert a new class buffer and grab its ID.
if (!dwClassID)
{
wchar_t wSQL[1024];
swprintf(wSQL, L"insert into %s (%s, %s) values (NULL, '%s') ",
lpTableName, pProp->wClassDataCol, pProp->wClassNameCol, lpClassName);
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(), wSQL);
IRowset *pRowset = NULL;
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"select @@identity", &pRowset, NULL);
if (SUCCEEDED(hr))
{
CReleaseMe r (pRowset);
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
hr = CSQLExecute::GetColumnValue(pRowset, 1, pMalloc, &pRow, vTemp);
hr = pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
pRow = NULL;
if (vTemp.vt == VT_I4)
dwClassID = vTemp.lVal;
else if (vTemp.vt == VT_BSTR)
dwClassID = _wtoi64(vTemp.bstrVal);
swprintf(wSQL, L"select %s from %s where %s = %ld ",
pProp->wClassDataCol, lpTableName,
pProp->wClassForeignKey, dwClassID);
hr = CSQLExecute::WriteImageValue(((COLEDBConnection *)pConn)->GetCommand(), wSQL, 1, pClassBuff, dwClassBuffLen);
}
}
return hr;
}
BOOL SetBooleanProp (LPWSTR lpPropName, IWbemClassObject *pProp)
{
BOOL bRet = FALSE;
LPWSTR lpTemp = GetPropertyVal(lpPropName, pProp);
if (lpTemp && wcslen(lpTemp))
bRet = _wtoi(lpTemp) == 0 ? FALSE : TRUE;
delete lpTemp;
return bRet;
}
LPWSTR FormatTableName(IWbemClassObject *pMapping, LPWSTR lpTableName = NULL)
{
LPWSTR lpRet = NULL;
BOOL bDelete = FALSE;
LPWSTR lpTbl = lpTableName;
if (!lpTbl)
{
bDelete = TRUE;
lpTbl = GetPropertyVal(L"sTableName", pMapping);
}
LPWSTR lpDB = GetPropertyVal(L"sDatabaseName", pMapping);
if (lpDB && wcslen(lpDB))
{
lpRet = new wchar_t [wcslen(lpTbl)+wcslen(lpDB)+5];
if (lpRet)
swprintf(lpRet, L"%s..%s", lpDB, lpTbl);
}
else
lpRet = Macro_CloneLPWSTR(lpTbl);
if (bDelete)
delete lpTbl;
return lpRet;
}
HRESULT LoadStringArray(LPWSTR lpPropName, IWbemClassObject *pProp, LPWSTR ** lpToSet, DWORD &dwNumElements)
{
HRESULT hr = WBEM_S_NO_ERROR;
VARIANT vTemp;
VariantInit(&vTemp);
hr = pProp->Get(lpPropName, 0, &vTemp, 0, 0);
if (SUCCEEDED(hr) && vTemp.vt != VT_NULL)
{
SAFEARRAY *pArray = V_ARRAY(&vTemp);
long lLBound1, lUBound1;
SafeArrayGetLBound(pArray, 1, &lLBound1);
SafeArrayGetUBound(pArray, 1, &lUBound1);
lUBound1 -= lLBound1;
lUBound1 += 1;
if (lUBound1 > 20)
hr = WBEM_E_INVALID_CLASS;
else
{
*lpToSet = new LPWSTR [lUBound1];
if (lpToSet)
{
dwNumElements = lUBound1;
for (int j = 0; j < lUBound1; j++)
{
VARIANT vT3;
VariantInit(&vT3);
hr = GetVariantFromArray(pArray, j, VT_BSTR, vT3);
if (SUCCEEDED(hr))
{
BSTR sTemp = V_BSTR(&vT3);
*lpToSet[j] = Macro_CloneLPWSTR(sTemp);
VariantClear(&vT3);
}
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
VariantClear(&vTemp);
}
else
{
*lpToSet = NULL;
dwNumElements = 0;
}
return hr;
}
HRESULT SetProps(LPWSTR lpTableName, MappedProperties *pPropDef, IWbemClassObject *pProp)
{
HRESULT hr = WBEM_S_NO_ERROR;
LPWSTR lpTemp = NULL;
pPropDef->wPropName = GetPropertyVal(L"sPropertyName", pProp);
pPropDef->wTableName = GetPropertyVal(L"sTableName", pProp);
pPropDef->wClassTable = GetPropertyVal(L"sClassTableName", pProp);
pPropDef->wClassNameCol = GetPropertyVal(L"sClassNameColumn", pProp);
pPropDef->wClassDataCol = GetPropertyVal(L"sClassDataColumn", pProp);
pPropDef->wClassForeignKey = GetPropertyVal(L"sClassForeignKey", pProp);
pPropDef->wScopeClass = GetPropertyVal(L"sScopeClass", pProp);
pPropDef->bReadOnly = SetBooleanProp(L"bReadOnly", pProp);
pPropDef->bStoreAsNumber = SetBooleanProp(L"bStoreAsNumber", pProp);
pPropDef->bDecompose = SetBooleanProp(L"bDecompose", pProp);
pPropDef->bIsKey = SetBooleanProp(L"bIsKey", pProp);
pPropDef->bStoreAsBlob = SetBooleanProp(L"bStoreAsBlob", pProp);
hr = LoadStringArray(L"arrColumnNames", pProp,
&pPropDef->arrColumnNames, pPropDef->dwNumColumns);
if (SUCCEEDED(hr))
{
hr = LoadStringArray(L"arrForeignKeys", pProp,
&pPropDef->arrForeignKeys, pPropDef->dwNumForeignKeys);
}
return hr;
}
HRESULT ConvertObjToStruct(IWbemClassObject *pMappingObj, MappedProperties **ppStruct, DWORD *NumProps)
{
HRESULT hr = WBEM_S_NO_ERROR;
VARIANT vTemp;
CClearMe c (&vTemp);
LPWSTR lpTableName = NULL;
lpTableName = GetPropertyVal(L"sTableName", pMappingObj);
CDeleteMe <wchar_t> d2 (lpTableName);
hr = pMappingObj->Get(L"arrProperties", 0, &vTemp, NULL, NULL);
if (SUCCEEDED(hr) && vTemp.vt == (VT_UNKNOWN + CIM_FLAG_ARRAY))
{
SAFEARRAY *psaArray = V_ARRAY(&vTemp);
if (psaArray)
{
long lLBound, lUBound;
SafeArrayGetLBound(psaArray, 1, &lLBound);
SafeArrayGetUBound(psaArray, 1, &lUBound);
lUBound -= lLBound;
lUBound += 1;
*ppStruct = new MappedProperties[lUBound];
if (*ppStruct)
{
MappedProperties *pProps = *ppStruct;
*NumProps = lUBound;
for (int i = 0; i < lUBound; i++)
{
VARIANT vT2;
VariantInit(&vT2);
hr = GetVariantFromArray(psaArray, i, VT_UNKNOWN, vT2);
IUnknown *pUnk = V_UNKNOWN(&vT2);
if (pUnk)
{
IWbemClassObject *pProp = NULL;
hr = pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pProp);
CReleaseMe r (pProp);
if (SUCCEEDED(hr))
{
hr = SetProps(lpTableName, &pProps[i], pProp);
}
}
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
hr = WBEM_E_INVALID_OBJECT;
return hr;
}
HRESULT AddObjToStruct(IWbemClassObject *pMappingObj, MappedProperties **ppStruct, DWORD dwCurrProps, DWORD *NumProps)
{
HRESULT hr = WBEM_S_NO_ERROR;
VARIANT vTemp;
CClearMe c (&vTemp);
DWORD dwNewSize = 0;
LPWSTR lpTableName = NULL;
lpTableName = GetPropertyVal(L"sTableName", pMappingObj);
CDeleteMe <wchar_t> d2 (lpTableName);
hr = pMappingObj->Get(L"arrProperties", 0, &vTemp, NULL, NULL);
if (SUCCEEDED(hr) && vTemp.vt == (VT_UNKNOWN + CIM_FLAG_ARRAY))
{
SAFEARRAY *psaArray = V_ARRAY(&vTemp);
if (psaArray)
{
long lLBound, lUBound;
SafeArrayGetLBound(psaArray, 1, &lLBound);
SafeArrayGetUBound(psaArray, 1, &lUBound);
lUBound -= lLBound;
lUBound += 1;
dwNewSize = dwCurrProps + lUBound;
*NumProps = dwNewSize;
MappedProperties *pProps = new MappedProperties[dwNewSize];
if (pProps)
{
memcpy(pProps, *ppStruct, sizeof(MappedProperties) * dwCurrProps);
delete *ppStruct;
*ppStruct = pProps;
for (int i = 0; i < lUBound; i++)
{
int iCurrPos = i + dwCurrProps;
VARIANT vT2;
VariantInit(&vT2);
hr = GetVariantFromArray(psaArray, i, VT_UNKNOWN, vT2);
IUnknown *pUnk = V_UNKNOWN(&vT2);
if (pUnk)
{
IWbemClassObject *pProp = NULL;
hr = pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pProp);
CReleaseMe r (pProp);
if (SUCCEEDED(hr))
{
hr = SetProps(lpTableName, &pProps[iCurrPos], pProp);
}
}
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
hr = WBEM_E_INVALID_OBJECT;
return hr;
}
_bstr_t GetDateTime(LPWSTR lpDMTFDate)
{
char szTmp[50];
wchar_t szTmp2[8];
wchar_t *p = lpDMTFDate;
int iYear = 0, iMonth = 0, iDay = 0, iHour=0, iMinute=0, iSecond=0;
if (lpDMTFDate && _wcsicmp(lpDMTFDate, L"null"))
{
wcsncpy(szTmp2, p, 4);
szTmp2[4] = '\0';
iYear = _wtoi(szTmp2);
p+=4;
wcsncpy(szTmp2, p, 2);
szTmp2[2] = '\0';
iMonth= _wtoi(szTmp2);
p+=2;
wcsncpy(szTmp2, p, 2);
szTmp2[2] = '\0';
iDay= _wtoi(szTmp2);
p+=2;
wcsncpy(szTmp2, p, 2);
szTmp2[2] = '\0';
iHour= _wtoi(szTmp2);
p+=2;
wcsncpy(szTmp2, p, 2);
szTmp2[2] = '\0';
iMinute= _wtoi(szTmp2);
p+=2;
wcsncpy(szTmp2, p, 2);
szTmp2[2] = '\0';
iSecond = _wtoi(szTmp2);
}
// This won't work with no delimiters...
// swscanf(lpDMTFDate, L"%04d%02d%02d%02d%02d02d.%06d",
// &iYear, &iMonth, &iDay, &iHour, &iMinute, &iSecond, &iMs);
if (iYear)
{
sprintf(szTmp, "%04d-%02d-%02d %02d:%02d:%02d",
iYear, iMonth, iDay, iHour, iMinute, iSecond);
}
else
strcpy(szTmp, "null");
return (const char *)szTmp;
}
LPWSTR GetColumnName(LPWSTR lpPropName, MappedProperties *pMapping, DWORD dwNumProps, BOOL *bQueriable, LPWSTR lpFunc = NULL,
SWQLNode *pFuncNode = NULL)
{
LPWSTR lpRet = NULL;
HRESULT hr = 0;
// Special case: datepart nodes contain the property name.
if (!lpPropName && pFuncNode)
{
lpPropName = ((SWQLNode_Datepart *)pFuncNode)->m_pColRef->m_pColName;
}
for (int i = 0; i < dwNumProps; i++)
{
if (!_wcsicmp(pMapping[i].wPropName, lpPropName))
{
// Queries on this type of column are invalid anyway.
if (pMapping[i].dwNumColumns > 1)
return NULL;
int iLen = wcslen(pMapping[i].arrColumnNames[0])+31;
if (lpFunc)
iLen += wcslen(lpFunc) + 1;
if (pFuncNode)
iLen += 10;
lpRet = new wchar_t [iLen];
if (lpRet)
{
lpRet[0] = L'\0';
BOOL bFinalParen = FALSE;
if (lpFunc)
{
if (!_wcsicmp(lpFunc, L"upper") ||
!_wcsicmp(lpFunc, L"lower") ||
!_wcsicmp(lpFunc, L"datepart"))
{
wcscpy(lpRet, lpFunc);
wcscat(lpRet, L"(");
bFinalParen = TRUE;
}
else
hr = WBEM_E_NOT_SUPPORTED;
}
if (pFuncNode && pFuncNode->m_dwNodeType == TYPE_SWQLNode_Datepart)
{
switch(((SWQLNode_Datepart *)pFuncNode)->m_nDatepart)
{
case WQL_TOK_YEAR:
wcscat(lpRet, L"yy,");
break;
case WQL_TOK_MONTH:
wcscat(lpRet, L"mm,");
break;
case WQL_TOK_DAY:
wcscat(lpRet, L"dd,");
break;
case WQL_TOK_HOUR:
wcscat(lpRet, L"hh,");
break;
case WQL_TOK_MINUTE:
wcscat(lpRet, L"minute,");
break;
case WQL_TOK_SECOND:
wcscat(lpRet, L"second,");
break;
case WQL_TOK_MILLISECOND:
wcscat(lpRet, L"ms,");
break;
default:
hr = WBEM_E_INVALID_QUERY;
break;
}
}
if (pMapping[i].wTableName && wcslen(pMapping[i].wTableName))
wcscat(lpRet, pMapping[i].wTableName);
else
wcscat(lpRet, L"a");
wcscat(lpRet, L".");
wcscat(lpRet, pMapping[i].arrColumnNames[0]);
if (bFinalParen)
wcscat(lpRet, L")");
if (!pMapping[i].bStoreAsBlob)
*bQueriable = TRUE;
break;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if (FAILED(hr))
{
delete lpRet;
lpRet = NULL;
}
return lpRet;
}
LPWSTR GetRefKey (LPWSTR lpIn, BOOL bStoreAsNumber, BOOL &bNeedQuotes)
{
LPWSTR lpRet = NULL;
LPWSTR lpIn2 = lpIn;
wchar_t *pTemp = new wchar_t [wcslen(lpIn) + 1];
if (!pTemp)
return NULL;
int iLen = wcslen(lpIn);
if (lpIn2[0] == L'\"')
{
iLen -= 2;
lpIn2 ++;
}
wcsncpy(pTemp, lpIn2, iLen);
pTemp[iLen] = L'\0';
IWbemPathKeyList *pKeyList = NULL;
IWbemPath *pPath = NULL;
HRESULT hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pPath);
if (SUCCEEDED(hr))
{
CReleaseMe r (pPath);
hr = pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, pTemp);
if (SUCCEEDED(hr))
{
hr = pPath->GetKeyList(&pKeyList);
if (SUCCEEDED(hr))
{
CReleaseMe r2 (pKeyList);
DWORD dwLen = 255;
DWORD dwLen2 = 255;
BYTE bBuff[255];
wchar_t wName[255];
ULONG ct;
hr = pKeyList->GetKey(0, 0, &dwLen, wName, &dwLen2, bBuff, &ct);
if (SUCCEEDED(hr))
{
if ((ct == CIM_STRING || ct == CIM_REFERENCE) && bStoreAsNumber)
bNeedQuotes = TRUE;
WCHAR * pTempx = new wchar_t [1024];
if (pTempx)
{
ConvertDataToString(pTempx, bBuff, ct);
lpRet = (WCHAR *)pTempx;
}
}
}
}
}
return lpRet;
}
BOOL IsEmbeddedProp (LPWSTR lpPropName)
{
BOOL bRet = FALSE;
WCHAR *pChar = NULL;
pChar = wcsstr(lpPropName, L".");
if (pChar)
bRet = TRUE;
pChar = wcsstr(lpPropName, L"[");
if (pChar)
bRet = TRUE;
return bRet;
}
HRESULT GetEmbeddedProp(IWbemClassObject *pObj, LPWSTR lpPropName, VARIANT *vValue, CIMTYPE *ct)
{
HRESULT hr = 0;
SAFEARRAY *pArray = NULL;
VARIANT vProp, vTemp;
VariantInit(&vProp);
VariantClear(&vTemp);
CClearMe c (&vProp), c1 (&vTemp);
CIMTYPE ctLocal = 0;
IUnknown *pUnk = NULL;
IWbemClassObject *pCurrent = pObj;
int iCurrPos = -1;
BOOL bArray = FALSE;
CTextLexSource src(lpPropName);
CGenLexer Lexer (WQL_LexTable, &src);
wchar_t wTemp[128];
pObj->AddRef();
int iCurrTok = Lexer.NextToken();
while (iCurrTok != OPATH_TOK_EOF)
{
switch(iCurrTok)
{
// Embedded object property.
case WQL_TOK_DOT:
bArray = FALSE;
// Retrieve the current embedded object.
hr = pCurrent->Get(wTemp, 0, &vProp, ct, NULL);
if (SUCCEEDED(hr) && vProp.vt == VT_UNKNOWN)
{
pUnk = V_UNKNOWN(&vProp);
if (pUnk)
{
pCurrent->Release();
pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pCurrent);
iCurrPos = -1;
pUnk->Release();
}
}
break;
// Array
case WQL_TOK_OPEN_BRACKET:
bArray = TRUE;
iCurrTok = Lexer.NextToken();
iCurrPos = _wtoi(Lexer.GetTokenText());
hr = pCurrent->Get(wTemp, 0, &vProp, ct, NULL);
if (SUCCEEDED(hr))
{
pArray = V_ARRAY(&vProp);
if (pArray && (vProp.vt & 0xFF) == VT_UNKNOWN)
{
hr = GetVariantFromArray(pArray, iCurrPos, (vProp.vt & 0xFF), vTemp);
pUnk = V_UNKNOWN(&vTemp);
if (pUnk)
{
pCurrent->Release();
pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pCurrent);
bArray = FALSE;
// This might reference an embedded-embedded object
iCurrTok = Lexer.NextToken(); // WQL_TOK_CLOSE_BRACKET
iCurrTok = Lexer.NextToken(); // WQL_TOK_DOT
iCurrTok = Lexer.NextToken(); // WQL_TOK_IDENT
iCurrTok = Lexer.NextToken(); // EOF or DOT
}
VariantClear(&vTemp);
}
}
break;
case WQL_TOK_CLOSE_BRACKET:
break;
case WQL_TOK_IDENT:
wcscpy(wTemp, Lexer.GetTokenText());
VariantClear(&vProp);
break;
}
iCurrTok = Lexer.NextToken();
if (FAILED(hr))
break;
}
// At this point, we should have the object in question.
// Retrieve the value depending on what it is.
if (bArray )
{
if (pArray)
hr = GetVariantFromArray(pArray, iCurrPos, (vProp.vt & 0xFF), *vValue);
}
else
{
if (pCurrent)
{
pCurrent->Get(wTemp, 0, vValue, ct, NULL);
pCurrent->Release();
}
}
*ct &= ~CIM_FLAG_ARRAY;
VariantClear(&vProp);
pObj->Release();
return hr;
}
HRESULT CWmiDbSession::GetEmbeddedClass (IWmiDbHandle *pScope, IWbemClassObject *pObj, LPWSTR lpEmbedProp,
IWbemClassObject **ppClass)
{
HRESULT hr = 0;
IWbemQualifierSet *pQS = NULL;
hr = pObj->GetPropertyQualifierSet(lpEmbedProp, &pQS);
if (SUCCEEDED(hr))
{
CReleaseMe r (pQS);
VARIANT vTemp;
CClearMe c (&vTemp);
hr = pQS->Get(L"cimtype", 0, &vTemp, NULL);
if (SUCCEEDED(hr))
{
if (vTemp.vt == VT_BSTR)
{
LPWSTR lpClassName = wcsstr(vTemp.bstrVal, L":")+1;
if (!lpClassName)
hr = WBEM_E_INVALID_CLASS;
else
{
IWmiDbHandle *pHandle = NULL;
LPWSTR lpNewPath = NULL;
IWbemPath *pPath = NULL;
hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pPath);
if (SUCCEEDED(hr))
{
CReleaseMe r8 (pPath);
if (pPath)
{
pPath->SetText(WBEMPATH_CREATE_ACCEPT_ALL, lpClassName);
hr = GetObject(pScope, pPath, 0, WMIDB_HANDLE_TYPE_STRONG_CACHE|WMIDB_HANDLE_TYPE_VERSIONED, &pHandle);
CReleaseMe r (pHandle);
if (SUCCEEDED(hr))
{
IWbemClassObject *pClass = NULL;
hr = pHandle->QueryInterface(IID_IWbemClassObject, (void **)&pClass);
if (SUCCEEDED(hr))
*ppClass = pClass;
}
}
}
}
}
}
}
return hr;
}
HRESULT CWmiDbSession::SetEmbeddedProp (IWmiDbHandle *pScope, LPWSTR lpPropName, IWbemClassObject *pObj,
VARIANT &vValue, CIMTYPE ct)
{
// Not so simple:
// The path must be traversed once to find it,
// then again in reverse and save the new value.
HRESULT hr = 0;
SAFEARRAY *pArray = NULL;
VARIANT vProp, vTemp;
VariantInit(&vProp);
VariantClear(&vTemp);
CClearMe c (&vProp), c1 (&vTemp);
CIMTYPE ctLocal = 0;
IUnknown *pUnk = NULL;
IWbemClassObject *pCurrent = pObj;
int iCurrPos = -1;
BOOL bArray = FALSE;
CIMTYPE ctCurr;
struct Prop
{
wchar_t wPropName[128];
int iPos;
CIMTYPE ct;
VARIANT vValue;
Prop(LPWSTR l, int i, CIMTYPE c, VARIANT* v)
{
wcscpy(wPropName, l);
iPos = i;
ct = c;
VariantInit(&vValue);
VariantCopy(&vValue, v);
}
~Prop()
{
VariantClear(&vValue);
}
};
CFlexArray arrProps;
CTextLexSource src(lpPropName);
CGenLexer Lexer (WQL_LexTable, &src);
wchar_t wTemp[128];
// Give ourself an extra ref count.
BOOL bAddRefed = FALSE;
int iCurrTok = Lexer.NextToken();
while (iCurrTok != OPATH_TOK_EOF)
{
switch(iCurrTok)
{
// Embedded object property.
case WQL_TOK_DOT:
if (!bAddRefed)
pObj->AddRef();
bAddRefed = TRUE;
bArray = FALSE;
// Retrieve the current embedded object.
hr = pCurrent->Get(wTemp, 0, &vProp, &ctCurr, NULL);
if (SUCCEEDED(hr))
{
pUnk = V_UNKNOWN(&vProp);
if (pUnk && vProp.vt == VT_UNKNOWN)
{
pCurrent->Release();
pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pCurrent);
}
else
{
IWbemClassObject *pNewObj = NULL;
IWbemClassObject *pClass = NULL;
hr = GetEmbeddedClass(pScope, pCurrent, wTemp, &pClass);
if (SUCCEEDED(hr))
{
hr = pClass->SpawnInstance(0, &pNewObj);
{
pCurrent->Release();
pCurrent = pNewObj;
V_UNKNOWN(&vProp) = pNewObj;
vProp.vt = VT_UNKNOWN;
}
}
}
iCurrPos = -1;
Prop *pProp = new Prop (wTemp, iCurrPos, ctCurr, &vProp);
if (!pProp)
hr = WBEM_E_OUT_OF_MEMORY;
else
arrProps.Add(pProp);
}
break;
// Array
case WQL_TOK_OPEN_BRACKET:
bArray = TRUE;
iCurrTok = Lexer.NextToken();
iCurrPos = _wtoi(Lexer.GetTokenText());
hr = pCurrent->Get(wTemp, 0, &vProp, &ctCurr, NULL);
if (SUCCEEDED(hr))
{
SAFEARRAY *pNew = NULL;
SAFEARRAYBOUND aBounds[1];
long lLBound, lUBound;
if (vProp.vt == VT_NULL)
{
// We have to create a new safearray.
// To avoid calculating the correct number of array elements,
// we need to use SafeArrayCopyData
aBounds[0].cElements = 1;
aBounds[0].lLbound = 0;
pArray = SafeArrayCreate(ctCurr & 0xFF, 1, aBounds);
}
else
{
pArray = V_ARRAY(&vProp);
SafeArrayGetLBound(pArray, 1, &lLBound);
SafeArrayGetUBound(pArray, 1, &lUBound);
lUBound -= lLBound;
lUBound += 2;
aBounds[0].cElements = lUBound;
aBounds[0].lLbound = 0;
pNew = SafeArrayCreate(ctCurr & 0xFF, 1, aBounds);
for (int i = 0; i < lUBound-1; i++)
{
void *data;
long lTemp[1];
lTemp[0] = i;
SafeArrayGetElement(pArray, lTemp, &data);
if ((ctCurr & 0xFFF) == CIM_STRING)
SafeArrayPutElement(pNew, lTemp, data);
else
SafeArrayPutElement(pNew, lTemp, &data);
}
SafeArrayDestroy(pArray);
pArray = pNew;
}
V_ARRAY(&vProp) = pArray;
vProp.vt = VT_ARRAY;
Prop *pProp = new Prop (wTemp, iCurrPos, ctCurr, &vProp);
if (pProp)
arrProps.Add(pProp);
else
hr = WBEM_E_OUT_OF_MEMORY;
if (pArray && (ctCurr & 0xFF) == CIM_OBJECT)
{
hr = GetVariantFromArray(pArray, iCurrPos, (vProp.vt & 0xFF), vTemp);
if (SUCCEEDED(hr) )
{
bArray = FALSE;
pUnk = V_UNKNOWN(&vTemp);
if (pUnk && (vProp.vt & 0xFF) == VT_UNKNOWN)
{
pCurrent->Release();
pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pCurrent);
// This might reference an embedded-embedded object
iCurrTok = Lexer.NextToken(); // WQL_TOK_CLOSE_BRACKET
iCurrTok = Lexer.NextToken(); // WQL_TOK_DOT
iCurrTok = Lexer.NextToken(); // WQL_TOK_IDENT
}
else
{
// We need to spawn an instance of whatever this is,
// assign it to our pCurrent pointer, and shove it
// in this array.
IWbemClassObject *pClass, *pNewObj = NULL;
hr = GetEmbeddedClass(pScope, pCurrent, wTemp, &pClass);
if (SUCCEEDED(hr))
{
hr = pClass->SpawnInstance(0, &pNewObj);
if (SUCCEEDED(hr))
{
pCurrent->Release();
pCurrent = pNewObj;
}
}
}
Prop *pProp = new Prop (Lexer.GetTokenText(), -1, VT_UNKNOWN, &vTemp);
if (pProp)
{
arrProps.Add(pProp);
iCurrTok = Lexer.NextToken(); // EOF or DOT
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
VariantClear(&vTemp);
}
}
break;
case WQL_TOK_CLOSE_BRACKET:
break;
case WQL_TOK_IDENT:
wcscpy(wTemp, Lexer.GetTokenText());
VariantClear(&vProp);
break;
}
iCurrTok = Lexer.NextToken();
if (FAILED(hr))
break;
}
// Now we have to go through and set each value.
// wTemp is our current property
// Set it in the last element of arrProps.
if (arrProps.Size() > 0)
{
Prop *pProp = (Prop *)arrProps.GetAt(arrProps.Size()-1);
if (bArray)
{
hr = PutVariantInArray(&pArray, pProp->iPos, &vValue);
VariantClear(&pProp->vValue);
V_ARRAY(&pProp->vValue) = pArray;
pProp->vValue.vt = VT_ARRAY | pProp->ct;
}
else
hr = pCurrent->Put(wTemp, 0, &vValue, ct);
for (int i = arrProps.Size() - 1; i > 0; i--)
{
Prop *pChild = (Prop *)arrProps.GetAt(i);
Prop *pParent = (Prop *)arrProps.GetAt(i-1);
if (pParent->iPos >= 0)
{
pArray = V_ARRAY(&pParent->vValue);
hr = PutVariantInArray(&pArray, pParent->iPos, &pChild->vValue);
}
else
{
IWbemClassObject *pTemp=NULL;
CReleaseMe r (pTemp);
pUnk = V_UNKNOWN(&pParent->vValue);
pUnk->QueryInterface(IID_IWbemClassObject, (void **)&pTemp);
hr = pTemp->Put(pChild->wPropName, 0, &pChild->vValue, pChild->ct);
}
}
// Finally, set the final element in the object
pProp = (Prop *)arrProps.GetAt(0);
hr = pObj->Put(pProp->wPropName, 0, &pProp->vValue, (bArray ? pProp->ct | CIM_FLAG_ARRAY : pProp->ct ));
}
else
hr = WBEM_E_INVALID_OBJECT;
for (int i = 0; i < arrProps.Size(); i++)
delete arrProps.GetAt(i);
if (pCurrent != pObj)
pCurrent->Release();
VariantClear(&vProp);
return hr;
}
HRESULT GetSelectClause(wchar_t *pSQL, MappedProperties *pProps, DWORD dwNumProps, SWQLNode *pColList = NULL)
{
wcscpy(pSQL, L" SELECT ");
BOOL bNeedComma = FALSE;
for (int i = 0; i < dwNumProps; i++)
{
for (int j = 0; j < pProps[i].dwNumColumns; j++)
{
BOOL bFound = TRUE;
if (pColList)
{
bFound = FALSE;
SWQLNode_ColumnList *pList = (SWQLNode_ColumnList *)pColList;
for (int i1 = 0; i1 < pList->m_aColumnRefs.Size(); i1++)
{
SWQLColRef *pColRef = (SWQLColRef *)pList->m_aColumnRefs.GetAt(i1);
if (!_wcsicmp(pColRef->m_pColName, pProps[i].wPropName) ||
!(_wcsicmp(pColRef->m_pColName, L"*")))
{
bFound = TRUE;
break;
}
}
}
else
{
bFound = TRUE;
}
if (!bFound)
break;
if (bNeedComma)
wcscat(pSQL, L",");
if (pProps[i].wTableName && wcslen(pProps[i].wTableName))
{
wcscat(pSQL, pProps[i].wTableName);
wcscat(pSQL, L".");
}
else
wcscat(pSQL, L"a.");
wcscat(pSQL, pProps[i].arrColumnNames[j]);
// Handle decomposed object columns.
if (pProps[i].bDecompose &&
pProps[i].wClassDataCol)
{
wcscat(pSQL, L",");
if (pProps[i].wClassTable && wcslen(pProps[i].wClassTable))
{
wcscat(pSQL, pProps[i].wClassTable);
wcscat(pSQL, L".");
}
else
wcscat(pSQL, L"a.");
wcscat(pSQL, pProps[i].wClassDataCol);
}
bNeedComma = TRUE;
}
}
return 0;
}
HRESULT GetFromClause(wchar_t *pSQL, IWbemClassObject *pMapping, MappedProperties *pProps, DWORD dwNumProps)
{
HRESULT hr = 0;
LPWSTR lpDatabaseName = NULL;
LPWSTR lpTableName = NULL, lpPK = NULL;
CWStringArray arrTables;
lpDatabaseName = GetPropertyVal(L"sDatabaseName", pMapping);
lpTableName = GetPropertyVal(L"sTableName", pMapping);
lpPK = GetPropertyVal(L"sPrimaryKeyCol", pMapping);
CDeleteMe <wchar_t> d1 (lpDatabaseName), d2 (lpTableName);
wcscpy(pSQL, L" FROM ");
if (lpDatabaseName && wcslen(lpDatabaseName))
{
wcscat(pSQL, lpDatabaseName);
wcscat(pSQL, L"..");
}
if (!lpTableName || !wcslen(lpTableName))
hr = WBEM_E_INVALID_OBJECT;
else
{
wcscat(pSQL, lpTableName);
wcscat(pSQL, L" AS a ");
if (!lpPK || !wcslen(lpPK))
{
for (int i = 0; i < dwNumProps; i++)
{
// BUGBUG: Compound primary keys!
if (pProps[i].bIsKey)
{
delete lpPK;
lpPK = new wchar_t [wcslen(pProps[i].arrColumnNames[0]) + 1];
if (lpPK)
wcscpy(lpPK, pProps[i].arrColumnNames[0]);
else
hr = WBEM_E_OUT_OF_MEMORY;
break;
}
}
}
for (int i = 0; i < dwNumProps; i++)
{
LPWSTR lpTable = pProps[i].wTableName;
if (lpTable &&
wcslen(lpTable) &&
_wcsicmp(lpTable, lpTableName))
{
BOOL bFound = FALSE;
for (int j = 0; j < arrTables.Size(); j++)
{
if (!_wcsicmp(arrTables.GetAt(j), lpTable))
bFound = TRUE;
}
if (!bFound)
{
wcscat(pSQL, L" LEFT OUTER JOIN ");
if (lpDatabaseName && wcslen(lpDatabaseName))
{
wcscat(pSQL, lpDatabaseName);
wcscat(pSQL, L"..");
}
wcscat(pSQL, lpTable);
wcscat(pSQL, L" AS " );
wcscat(pSQL, lpTable);
wcscat(pSQL, L" ON ");
wcscat(pSQL, lpTable);
wcscat(pSQL, L".");
if (pProps[i].arrForeignKeys)
wcscat(pSQL, pProps[i].arrForeignKeys[0]); //BUGBUG: Compound foreign key columns!
else if (lpPK)
wcscat(pSQL, lpPK);
else
hr = WBEM_E_INVALID_OPERATION;
wcscat(pSQL, L" = ");
wcscat(pSQL, L"a.");
if (pProps[i].bDecompose && pProps[i].arrForeignKeys)
wcscat(pSQL, pProps[i].arrForeignKeys[0]);
else if (lpPK)
wcscat(pSQL, lpPK);
else
hr = WBEM_E_INVALID_OPERATION;
arrTables.Add(lpTable);
}
}
if (pProps[i].bDecompose && pProps[i].wClassTable)
{
lpTable = pProps[i].wClassTable;
BOOL bFound = FALSE;
for (int j = 0; j < arrTables.Size(); j++)
{
if (!_wcsicmp(arrTables.GetAt(j), lpTable))
bFound = TRUE;
}
if (!bFound)
{
if (!pProps[i].wClassForeignKey)
hr = WBEM_E_INVALID_OPERATION;
else
{
wcscat(pSQL, L" LEFT OUTER JOIN ");
if (lpDatabaseName && wcslen(lpDatabaseName))
{
wcscat(pSQL, lpDatabaseName);
wcscat(pSQL, L"..");
}
wcscat(pSQL, lpTable);
wcscat(pSQL, L" AS " );
wcscat(pSQL, lpTable);
wcscat(pSQL, L" ON ");
wcscat(pSQL, lpTable);
wcscat(pSQL, L".");
wcscat(pSQL, pProps[i].wClassForeignKey);
wcscat(pSQL, L" = ");
wcscat(pSQL, L"a.");
wcscat(pSQL, pProps[i].wClassForeignKey); // One screwy case, since the class table is the parent!
arrTables.Add(lpTable);
}
}
}
}
}
delete lpPK;
return hr;
}
HRESULT GetWhereClause(wchar_t *pSQL, IWbemClassObject *pMapping, IWbemClassObject *pClass,
IWbemPath *pPath, MappedProperties *pProps, DWORD dwNumProps)
{
HRESULT hr = 0;
BOOL bNeedWhere = TRUE;
wcscpy(pSQL, L"");
IWbemPathKeyList *pKeyList = NULL;
hr = pPath->GetKeyList(&pKeyList);
CReleaseMe r (pKeyList);
if (SUCCEEDED(hr))
{
for (int i = 0; i < dwNumProps; i++)
{
if (pProps[i].bIsKey)
{
BOOL bFound = FALSE;
BYTE bBuff[255];
wchar_t *pName = new wchar_t [255];
if (!pName)
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe <wchar_t> d (pName);
ULONG ct1;
ULONG uCount;
pKeyList->GetCount(&uCount);
for (ULONG j = 0; j < uCount; j++)
{
DWORD dwLen2 = 255;
DWORD dwLen = 255;
hr = pKeyList->GetKey(j, 0, &dwLen, pName, &dwLen2, bBuff, &ct1);
if (SUCCEEDED(hr) && (!wcslen(pName) || !_wcsicmp(pName, pProps[i].wPropName)))
{
if (bNeedWhere)
wcscpy(pSQL, L" WHERE ");
else
wcscat(pSQL, L" AND ");
bNeedWhere = FALSE;
CIMTYPE ct;
pClass->Get(pProps[i].wPropName, 0, NULL, &ct, NULL);
BOOL bNeedQuotes = FALSE;
if (ct == CIM_STRING || ct == CIM_DATETIME)
{
if (!pProps[i].bStoreAsNumber)
bNeedQuotes = TRUE;
}
WCHAR * pTempx = new wchar_t [1024];
if (!pTempx)
return WBEM_E_OUT_OF_MEMORY;
ConvertDataToString(pTempx, bBuff, ct);
if (SUCCEEDED(hr))
{
if (ct == CIM_REFERENCE)
{
// Need to extract the value(s)
// out of the object path.
// Ignoring compound keys for now.
LPWSTR lpTemp = GetRefKey(pTempx, pProps[i].bStoreAsNumber, bNeedQuotes);
if (lpTemp)
{
delete pTempx;
pTempx = lpTemp;
}
else
{
delete pTempx;
hr = WBEM_E_OUT_OF_MEMORY;
break;
}
}
CDeleteMe <wchar_t> d (pTempx);
wcscat(pSQL, L"a.");
wcscat(pSQL, pProps[i].arrColumnNames[0]); //BUGBUG: Compound foreign keys
wcscat(pSQL, L"=");
if (bNeedQuotes)
wcscat(pSQL, L"'");
wcscat(pSQL, pTempx);
if (bNeedQuotes)
wcscat(pSQL, L"'");
bFound = TRUE;
break;
}
}
}
if (!bFound)
{
hr = WBEM_E_INVALID_PARAMETER;
break;
}
}
}
}
return hr;
}
HRESULT GetWhereClause(wchar_t *pSQL, IWbemClassObject *pMapping, IWbemClassObject *pInst,
MappedProperties *pProps, DWORD dwNumProps, LPWSTR lpKeyColName=NULL)
{
HRESULT hr = 0;
wcscpy(pSQL, L"");
BOOL bNeedWhere = TRUE;
for (int i = 0; i < dwNumProps; i++)
{
if (pProps[i].bIsKey)
{
if (bNeedWhere)
wcscpy(pSQL, L" WHERE ");
else
wcscat(pSQL, L" AND ");
bNeedWhere = FALSE;
VARIANT vTemp;
CIMTYPE ct;
VariantInit(&vTemp);
CClearMe c (&vTemp);
pInst->Get(pProps[i].wPropName, 0, &vTemp, &ct, NULL);
BOOL bNeedQuotes = FALSE;
if (ct == CIM_STRING || ct == CIM_DATETIME)
{
if (!pProps[i].bStoreAsNumber)
bNeedQuotes = TRUE;
}
if (lpKeyColName)
wcscat(pSQL, lpKeyColName);
else
wcscat(pSQL, pProps[i].arrColumnNames[0]); //BUGBUG: Compound primary key
wcscat(pSQL, L"=");
LPWSTR lpTemp;
lpTemp = GetStr(vTemp);
if (ct == CIM_REFERENCE)
{
// Need to extract the value(s)
// out of the object path.
// Ignoring compound keys for now.
LPWSTR lpTmp = GetRefKey(lpTemp, pProps[i].bStoreAsNumber, bNeedQuotes);
delete lpTemp;
lpTemp = lpTmp;
}
CDeleteMe <wchar_t> d1 (lpTemp);
if (bNeedQuotes)
wcscat(pSQL, L"'");
if (ct == CIM_DATETIME)
wcscat(pSQL, (const wchar_t *)GetDateTime(lpTemp));
else
wcscat(pSQL, lpTemp);
if (bNeedQuotes)
wcscat(pSQL, L"'");
}
}
return hr;
}
HRESULT GetDeleteClause(wchar_t *pSQL, IWbemClassObject *pMapping, IWbemClassObject *pInst,
MappedProperties *pProps, DWORD dwNumProps)
{
HRESULT hr = 0;
LPWSTR lpTableName = GetPropertyVal(L"sTableName", pMapping);
LPWSTR lpDatabase = GetPropertyVal(L"sDatabaseName", pMapping);
CWStringArray arrTables;
wchar_t wWhere[1024];
CDeleteMe <wchar_t> d1 (lpTableName), d2 (lpDatabase);
wcscpy(pSQL, L"");
// Delete from any other tables.
for (int i = 0; i < dwNumProps; i++)
{
BOOL bFound = FALSE;
if (pProps[i].wTableName && wcslen(pProps[i].wTableName) && _wcsicmp(pProps[i].wTableName, lpTableName))
{
for (int j = 0; j < arrTables.Size(); j++)
{
if (!_wcsicmp(pProps[i].wTableName, arrTables.GetAt(j)))
{
bFound = TRUE;
break;
}
}
if (!bFound)
{
LPWSTR lpKey = NULL;
if (pProps[i].arrForeignKeys)
lpKey = pProps[i].arrForeignKeys[0];
GetWhereClause(wWhere, pMapping, pInst, pProps, dwNumProps, lpKey);
wcscat(pSQL, L" DELETE from ");
if (lpDatabase && wcslen(lpDatabase))
{
wcscat(pSQL, lpDatabase);
wcscat(pSQL, L"..");
}
wcscat(pSQL, pProps[i].wTableName);
wcscat(pSQL, wWhere);
arrTables.Add(pProps[i].wTableName);
}
}
if (pProps[i].wClassTable && wcslen(pProps[i].wClassTable))
{
GetWhereClause(wWhere, pMapping, pInst, pProps, dwNumProps, pProps[i].wClassForeignKey);
wcscat(pSQL, L" DELETE from ");
if (lpDatabase && wcslen(lpDatabase))
{
wcscat(pSQL, lpDatabase);
wcscat(pSQL, L"..");
}
wcscat(pSQL, pProps[i].wClassTable);
wcscat(pSQL, wWhere);
arrTables.Add(pProps[i].wClassTable);
}
}
hr = GetWhereClause(wWhere, pMapping, pInst, pProps, dwNumProps);
wcscat(pSQL, L" DELETE from ");
if (lpDatabase && wcslen(lpDatabase))
{
wcscat(pSQL, lpDatabase);
wcscat(pSQL, L"..");
}
wcscat(pSQL, lpTableName);
wcscat(pSQL, wWhere);
return 0;
}
HRESULT GetUpdateClause(wchar_t *pSQL, IWbemClassObject *pMapping, IWbemClassObject *pObj,
MappedProperties *pProps, DWORD dwNumProps, LPWSTR lpTableName,
BOOL bBaseTable = TRUE)
{
HRESULT hr = 0;
BOOL bNeedComma = FALSE;
LPWSTR lpDatabase = GetPropertyVal(L"sDatabaseName", pMapping);
CDeleteMe <wchar_t> d (lpDatabase);
wcscpy(pSQL, L"UPDATE ");
if (lpDatabase && wcslen(lpDatabase))
{
wcscat(pSQL, lpDatabase);
wcscat(pSQL, L"..");
}
wcscat(pSQL, lpTableName);
wcscat(pSQL, L" set ");
for (int i = 0; i < dwNumProps; i++)
{
int iTableLen = 0;
if (pProps[i].wTableName)
iTableLen = wcslen(pProps[i].wTableName);
if (!pProps[i].bReadOnly &&
((bBaseTable && !iTableLen) ||
(iTableLen && !_wcsicmp(pProps[i].wTableName, lpTableName))))
{
VARIANT vTemp;
CIMTYPE ct;
CClearMe c (&vTemp);
if (IsEmbeddedProp(pProps[i].wPropName))
hr = GetEmbeddedProp(pObj, pProps[i].wPropName, &vTemp, &ct);
else
hr = pObj->Get(pProps[i].wPropName, 0, &vTemp, &ct, NULL);
if (SUCCEEDED(hr))
{
BOOL bNull = FALSE;
BOOL bNeedQuotes = FALSE;
if (ct == CIM_STRING || ct == CIM_DATETIME)
{
if (!pProps[i].bStoreAsNumber)
bNeedQuotes = TRUE;
}
LPWSTR lpVal = NULL;
if (!pProps[i].bStoreAsBlob)
lpVal = GetStr(vTemp);
if (ct == CIM_REFERENCE)
{
LPWSTR lpTmp = GetRefKey(lpVal, pProps[i].bStoreAsNumber, bNeedQuotes);
delete lpVal;
lpVal = lpTmp;
}
CDeleteMe <wchar_t> d1 (lpVal);
if (!lpVal || !wcslen(lpVal))
bNull = TRUE;
if (bNeedComma)
wcscat(pSQL, L",");
bNeedComma = TRUE;
wcscat(pSQL, pProps[i].arrColumnNames[0]); // BUGBUG: compound primary key
wcscat(pSQL, L"=");
if (bNeedQuotes && !bNull)
wcscat(pSQL, L"'");
if (ct == CIM_DATETIME)
wcscat(pSQL, (const wchar_t *)GetDateTime(lpVal));
else if (bNull)
wcscat(pSQL, L"null");
else
wcscat(pSQL, lpVal);
if (bNeedQuotes && !bNull)
wcscat(pSQL, L"'");
}
else
break;
}
}
wchar_t wTemp[1024];
hr = GetWhereClause(wTemp, pMapping, pObj, pProps, dwNumProps);
wcscat(pSQL, wTemp);
return hr;
}
HRESULT GetInsertClause(wchar_t *pSQL, IWbemClassObject *pMapping, IWbemClassObject *pObj,
MappedProperties *pProps, DWORD dwNumProps, BOOL *bRetVal,
LPWSTR lpTableName, BOOL bBaseTable = TRUE)
{
HRESULT hr = 0;
BOOL bNeedComma = FALSE;
wchar_t wPrefix[255], wSuffix[255], wInsert[1024];
BOOL bNeedRetVal = FALSE;
LPWSTR lpDatabase = GetPropertyVal(L"sDatabaseName", pMapping);
LPWSTR lpPK = GetPropertyVal(L"sPrimaryKeyCol", pMapping);
CDeleteMe <wchar_t> d (lpDatabase), d3(lpPK);
wcscpy(wPrefix, L"set nocount on declare @RetVal varchar(50) ");
if (lpPK && wcslen(lpPK))
{
wcscpy(wSuffix, L" select @RetVal = @@identity ");
bNeedRetVal = TRUE;
}
else
wcscpy(wSuffix, L"");
wcscpy(wInsert, L"INSERT INTO ");
if (lpDatabase && wcslen(lpDatabase))
{
wcscat(wInsert, lpDatabase);
wcscat(wInsert, L"..");
}
wcscat(wInsert, lpTableName);
wcscat(wInsert, L" ( ");
for (int i = 0; i < dwNumProps; i++)
{
if (pProps[i].bReadOnly)
continue;
int iTableLen = 0;
if (pProps[i].wTableName)
iTableLen = wcslen(pProps[i].wTableName);
if ((((bBaseTable && !iTableLen) ||
(iTableLen && !_wcsicmp(pProps[i].wTableName, lpTableName)))) ||
(!bBaseTable && pProps[i].bIsKey))
{
if (bNeedComma)
wcscat(wInsert, L",");
bNeedComma = TRUE;
wcscat(wInsert, pProps[i].arrColumnNames[0]); // BUGBUG: Compound columns
}
}
wcscat(wInsert, L") values (");
bNeedComma = FALSE;
for (i = 0; i < dwNumProps; i++)
{
int iTableLen = 0;
if (pProps[i].wTableName)
iTableLen = wcslen(pProps[i].wTableName);
if ((((bBaseTable && !iTableLen) ||
(iTableLen && !_wcsicmp(pProps[i].wTableName, lpTableName)))) ||
(!bBaseTable && pProps[i].bIsKey))
{
VARIANT vTemp;
CIMTYPE ct;
CClearMe c (&vTemp);
if (IsEmbeddedProp(pProps[i].wPropName))
hr = GetEmbeddedProp(pObj, pProps[i].wPropName, &vTemp, &ct);
else
hr = pObj->Get(pProps[i].wPropName, 0, &vTemp, &ct, NULL);
if (SUCCEEDED(hr))
{
BOOL bNull = FALSE;
IWbemQualifierSet *pQS = NULL;
pObj->GetPropertyQualifierSet(pProps[i].wPropName, &pQS);
CReleaseMe r (pQS);
BOOL bNeedQuotes = FALSE;
if (ct == CIM_STRING || ct == CIM_DATETIME)
{
if (!pProps[i].bStoreAsNumber)
bNeedQuotes = TRUE;
}
LPWSTR lpVal = NULL;
if (!pProps[i].bStoreAsBlob)
lpVal = GetStr(vTemp);
if (pQS)
{
DWORD dwKeyholeFlag = GetQualifierFlag(L"keyhole", pQS);
if (dwKeyholeFlag)
{
bNeedRetVal = TRUE;
if (bRetVal)
*bRetVal = TRUE;
if (ct == CIM_STRING && !(pProps[i].bStoreAsNumber))
{
bNeedQuotes = FALSE;
delete lpVal;
lpVal = new wchar_t [10];
if (lpVal)
wcscpy(lpVal, L"@RetVal");
wcscpy(wSuffix, L"");
wcscat(wPrefix, L" select @RetVal = convert(varchar(50),newid()) ");
}
else
{
wcscpy(wSuffix, L" select @RetVal = convert(varchar(50), @@identity) ");
delete lpVal;
continue; // identity columns must be read-only.
}
}
else if (pProps[i].bReadOnly)
{
delete lpVal;
continue;
}
}
if (ct == CIM_REFERENCE)
{
// Need to extract the value(s)
// out of the object path.
// Ignoring compound keys for now.
LPWSTR lpTmp = GetRefKey(lpVal, pProps[i].bStoreAsNumber, bNeedQuotes);
delete lpVal;
lpVal = lpTmp;
}
CDeleteMe <wchar_t> d (lpVal);
if (bNeedComma)
wcscat(wInsert, L",");
bNeedComma = TRUE;
if (!lpVal || !wcslen(lpVal))
bNull = TRUE;
if (bNeedQuotes && !bNull)
wcscat(wInsert, L"'");
if (ct == CIM_DATETIME)
wcscat(wInsert, (const wchar_t *)GetDateTime(lpVal));
else if (bNull)
wcscat(wInsert, L"null");
else
wcscat(wInsert, lpVal);
if (bNeedQuotes && !bNull)
wcscat(wInsert, L"'");
delete lpVal;
}
else
break;
}
}
wcscat(wInsert, L")");
if (SUCCEEDED(hr))
{
swprintf(pSQL, L"%s %s %s", wPrefix, wInsert, wSuffix);
if (bNeedRetVal)
wcscat(pSQL, L"select @RetVal");
}
return hr;
}
HRESULT GetPutClause (wchar_t *pSQL, IWbemClassObject *pMapping, IWbemClassObject *pObj,
MappedProperties *pProps, DWORD dwNumProps, LPWSTR lpTableName,
LPWSTR lpKeyholeVal, int iTablePos)
{
// This function needs to format an IF ... ELSE statement
// lpKeyholeVal is the new value, if its not present
// in the object (e.g., implicit keys).
wchar_t wTemp[1024];
BOOL bNeedComma = FALSE;
wchar_t wTable[128];
HRESULT hr = 0;
LPWSTR lpDatabase = GetPropertyVal(L"sDatabaseName", pMapping);
CDeleteMe <wchar_t> d (lpDatabase);
if (lpDatabase && wcslen(lpDatabase))
swprintf(wTable, L"%s..%s", lpDatabase, lpTableName);
else
wcscpy(wTable, lpTableName);
// If this is an implicit key, use the new keyhole value.
if (!lpKeyholeVal || !wcslen(lpKeyholeVal) ||
!pProps[iTablePos].arrForeignKeys || !wcslen(pProps[iTablePos].arrForeignKeys[0]))
hr = GetWhereClause(wTemp, pMapping, pObj, pProps, dwNumProps);
else
swprintf(wTemp, L" WHERE %s = '%s'", pProps[iTablePos].arrForeignKeys[0], lpKeyholeVal);
swprintf(pSQL, L" IF EXISTS (select * from %s %s) ", wTable, wTemp);
// UPDATE
hr = GetUpdateClause(wTemp, pMapping, pObj, pProps, dwNumProps, lpTableName, FALSE);
wcscat(pSQL, L" ");
wcscat(pSQL, wTemp);
wcscat(pSQL, L" ELSE BEGIN ");
// INSERT
hr = GetInsertClause(wTemp, pMapping, pObj, pProps, dwNumProps, NULL, lpTableName, FALSE);
wcscat(pSQL, wTemp);
wcscat(pSQL, L" END ");
return hr;
}
HRESULT GetOrderByClause(SWQLNode_ColumnList *pList, _bstr_t &sSQL, MappedProperties *pProps,DWORD dwNumProps)
{
BOOL bQueriable = FALSE;
sSQL = L" order by ";
BOOL bNeedComma = FALSE;
for (int i = 0; i < pList->m_aColumnRefs.Size(); i++)
{
SWQLColRef *pRef = (SWQLColRef *)pList->m_aColumnRefs.GetAt(i);
if (bNeedComma)
sSQL += L",";
LPWSTR lpColName = GetColumnName(pRef->m_pColName, pProps, dwNumProps, &bQueriable);
if (lpColName)
{
CDeleteMe <wchar_t> d (lpColName);
sSQL += lpColName;
bNeedComma = TRUE;
}
else
bNeedComma = FALSE;
}
return 0;
}
HRESULT CWmiDbSession::CustomSetProperties (IWmiDbHandle *pScope, IRowset *pRowset, IMalloc *pMalloc,
IWbemClassObject *pClassObj, MappedProperties *pProps,
DWORD dwNumProps, IWbemClassObject *pObj)
{
HRESULT hr = 0;
int j;
if (SUCCEEDED(hr))
{
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
int iCurrPos = 0;
while (hr == WBEM_S_NO_ERROR)
{
LPWSTR lpColumnName = NULL;
hr = CSQLExecute::GetColumnValue(pRowset, iCurrPos+1, pMalloc, &pRow, vTemp, &lpColumnName);
if (hr != WBEM_S_NO_ERROR)
{
if (iCurrPos)
hr = WBEM_S_NO_ERROR;
else
hr = WBEM_E_NOT_FOUND;
break;
}
CDeleteMe <wchar_t> d (lpColumnName);
BOOL bMatch = FALSE;
MappedProperties *pThis = NULL;
for (; iCurrPos < dwNumProps; iCurrPos++)
{
for (int j = 0; j < pProps[iCurrPos].dwNumColumns; j++)
{
if (!_wcsicmp(lpColumnName, pProps[iCurrPos].arrColumnNames[j]) ||
(pProps[iCurrPos].wClassDataCol &&
!_wcsicmp(lpColumnName, pProps[iCurrPos].wClassDataCol)))
{
bMatch = TRUE;
pThis = &pProps[iCurrPos];
break;
}
}
if (bMatch)
break;
}
if (bMatch)
{
CIMTYPE ct = 0;
pClassObj->Get(pThis->wPropName, 0, NULL, &ct, NULL);
// Handle blobs.
if (pThis->bStoreAsBlob)
{
BYTE *pBuffer = NULL;
DWORD dwLen = 0;
long why[1];
unsigned char t;
IWbemClassObject *pObj3 = NULL;
_IWmiObject *pInt = NULL;
SAFEARRAY* pArray = NULL, *pArrayNew;
SAFEARRAYBOUND aBounds[1];
hr = CSQLExecute::ReadImageValue(pRowset, iCurrPos+1, &pRow, &pBuffer, dwLen);
if (SUCCEEDED(hr) && dwLen)
{
LPVOID pTaskMem = NULL;
switch(ct)
{
case CIM_FLAG_ARRAY+CIM_UINT8:
aBounds[0].cElements = dwLen; // This *should* be the max value!!!!
aBounds[0].lLbound = 0;
pArray = SafeArrayCreate(VT_UI1, 1, aBounds);
for (j = 0; j < dwLen; j++)
{
why[0] = j;
t = pBuffer[j];
hr = SafeArrayPutElement(pArray, why, &t);
}
vTemp.vt = VT_ARRAY+VT_UI1;
V_ARRAY(&vTemp) = pArray;
CWin32DefaultArena::WbemMemFree(pBuffer);
break;
case CIM_FLAG_ARRAY + CIM_OBJECT:
pArray = (SAFEARRAY *)pBuffer;
SafeArrayCopy(pArray, &pArrayNew);
V_ARRAY(&vTemp) = pArrayNew;
vTemp.vt = VT_ARRAY+VT_UNKNOWN;
CWin32DefaultArena::WbemMemFree(pBuffer);
break;
case CIM_OBJECT:
vTemp.vt = VT_UNKNOWN;
hr = pClassObj->SpawnInstance(0, &pObj3);
if (SUCCEEDED(hr))
{
hr = pObj3->QueryInterface(IID__IWmiObject, (void **)&pInt);
// Allocate COM memory before we pass to SetObjectMemory() - This
// will acquire the memory and free the blob.
if (SUCCEEDED(hr))
{
CReleaseMe r (pObj3);
pTaskMem = CoTaskMemAlloc( dwLen );
if ( NULL != pTaskMem )
{
// COpy the memory
CopyMemory( pTaskMem, pBuffer, dwLen );
// If this is a decomposed embedded object, must reassemble here.
if (pThis->bDecompose)
{
// Read this part (instance part)
// Read next part (class part)
// recombine them and shove them in the instance
hr = pInt->SetObjectParts(pTaskMem, dwLen, WBEM_OBJ_INSTANCE_PART|WBEM_OBJ_DECORATION_PART);
if (SUCCEEDED(hr))
{
BYTE *pBuff = NULL;
DWORD dwLen2 = 0;
iCurrPos++; // Skip to next row.
hr = CSQLExecute::ReadImageValue(pRowset, iCurrPos+1, &pRow, &pBuff, dwLen2);
if (SUCCEEDED(hr))
{
CDeleteMe <BYTE> d (pBuff);
LPVOID pTaskMem2 = CoTaskMemAlloc(dwLen2);
if (pTaskMem)
{
CopyMemory(pTaskMem2, pBuff, dwLen2);
hr = pInt->SetClassPart(pTaskMem2, dwLen2);
if (SUCCEEDED(hr))
{
V_UNKNOWN(&vTemp) = pInt;
pInt->AddRef();
// We evidently don't need to free the buffers,
// since SetObjectParts acquires the memory.
}
}
}
}
}
else
{
hr = pInt->SetObjectMemory(pTaskMem, dwLen);
if (SUCCEEDED(hr))
{
V_UNKNOWN(&vTemp) = (IUnknown *)pInt;
pInt->AddRef();
}
}
}
else
{
pObj3->Release();
CoTaskMemFree(pTaskMem);
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
pObj3->Release();
}
// Free the buffer
CWin32DefaultArena::WbemMemFree(pBuffer);
break;
default:
CSQLExecute::SetVariant(CIM_STRING, &vTemp, pBuffer, ct);
break;
}
hr = pObj->Put(pThis->wPropName, 0, &vTemp, ct);
if (!pThis->bDecompose)
CoTaskMemFree(pTaskMem);
}
else
hr = WBEM_S_PARTIAL_RESULTS;
}
else
{
if (ct == CIM_REFERENCE)
{
// Need to construct the object path
// from the data in this column.
wchar_t wNewPath[1024];
LPWSTR lpClassName = NULL;
LPWSTR lpTemp = GetStr(vTemp);
CDeleteMe <wchar_t> d(lpTemp), d2 (lpClassName);
// Get the class name out of the
// CIMTYPE qualifier
// =============================
VARIANT vVal;
VariantInit(&vVal);
IWbemQualifierSet *pQS = NULL;
pObj->GetPropertyQualifierSet(pThis->wPropName, &pQS);
CReleaseMe r (pQS);
hr = pQS->Get(L"cimtype", 0, &vVal, NULL);
lpClassName = wcsstr(vVal.bstrVal, L":")+1;
if (vTemp.vt == VT_BSTR)
swprintf(wNewPath, L"%s=\"%s\"", lpClassName, lpTemp);
else
swprintf(wNewPath, L"%s=%s", lpClassName, lpTemp);
VariantClear(&vTemp);
VariantClear(&vVal);
vTemp.vt = VT_BSTR;
vTemp.bstrVal = SysAllocString(wNewPath);
}
if (IsEmbeddedProp(pThis->wPropName))
hr = SetEmbeddedProp(pScope, pThis->wPropName, pObj, vTemp, ct);
else
hr = pObj->Put(pThis->wPropName, 0, &vTemp, ct);
}
VariantClear(&vTemp);
}
iCurrPos++;
if (iCurrPos >= dwNumProps)
break;
}
pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
if (SUCCEEDED(hr) && pObj)
{
hr = GetSchemaCache()->DecorateWbemObj(m_sMachineName, m_sNamespacePath,
((CWmiDbHandle *)pScope)->m_dObjectId, pObj, 0);
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CustomGetObject
//
//***************************************************************************
HRESULT CWmiDbSession::CustomGetObject(IWmiDbHandle *pScope, IWbemPath *pPath, LPWSTR lpObjectKey,
DWORD dwFlags, DWORD dwRequestedHandleType, IWmiDbHandle **ppResult)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemClassObject *pObj = NULL;
DWORD dwLen = 512;
wchar_t wClassName[512];
pPath->GetClassName(&dwLen, wClassName);
IWbemClassObject *pMappingObj = NULL;
BOOL bDone = FALSE;
SQL_ID dObjId = 0, dClassId = 0;
LPWSTR lpKeyString = GetKeyString(lpObjectKey);
CDeleteMe <wchar_t> d (lpKeyString);
if (lpKeyString)
{
dObjId = CRC64::GenerateHashValue(lpKeyString);
hr = GetObjectCache()->GetObject(dObjId, &pObj);
if (SUCCEEDED(hr))
{
if (m_pController)
((CWmiDbController *)m_pController)->IncrementHitCount(true);
bDone = TRUE;
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
if (!bDone)
{
// Get a SQL connection.
IWmiDbHandle *pClassHandle = NULL;
IWbemPath *pParser = NULL;
hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pParser);
CReleaseMe r2 (pParser);
if (SUCCEEDED(hr))
{
pParser->SetText(WBEMPATH_CREATE_ACCEPT_ALL, wClassName);
hr = GetObject(pScope, pParser, 0, WMIDB_HANDLE_TYPE_STRONG_CACHE|WMIDB_HANDLE_TYPE_VERSIONED, &pClassHandle);
CReleaseMe r1 (pClassHandle);
if (SUCCEEDED(hr))
{
dClassId = ((CWmiDbHandle *)pClassHandle)->m_dObjectId;
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn);
if (SUCCEEDED(hr))
{
hr = CustomGetMapping(pConn, pScope, wClassName, &pMappingObj);
if (SUCCEEDED(hr))
{
IWbemClassObject *pClassObj = NULL;
pClassHandle->QueryInterface(IID_IWbemClassObject, (void **)&pClassObj);
CReleaseMe r2 (pClassObj);
if (pClassObj)
{
hr = pClassObj->SpawnInstance(0, &pObj);
if (SUCCEEDED(hr))
{
CWStringArray arrKeyValues;
if (SUCCEEDED(hr))
{
wchar_t * pSQL = new wchar_t [2048];
CDeleteMe <wchar_t> d (pSQL);
if (!pSQL)
{
GetSQLCache()->ReleaseConnection(pConn);
return WBEM_E_OUT_OF_MEMORY;
}
MappedProperties *pProps = NULL;
DWORD dwNumProps;
BOOL bNeedWhere = TRUE;
// See if there are any parents, and if
// any of them are mapped.
hr = ConvertObjToStruct(pMappingObj, &pProps, &dwNumProps);
CDeleteMe <MappedProperties> d1 (pProps);
if (SUCCEEDED(hr))
{
VARIANT vTemp;
CClearMe c (&vTemp);
hr = pObj->Get(L"__Derivation", 0, &vTemp, NULL, NULL);
SAFEARRAY *psaArray = V_ARRAY(&vTemp);
if (psaArray)
{
long lLBound, lUBound;
SafeArrayGetLBound(psaArray, 1, &lLBound);
SafeArrayGetUBound(psaArray, 1, &lUBound);
lUBound -= lLBound;
lUBound += 1;
for (int i = 0; i < lUBound; i++)
{
IWbemClassObject *pMapping2 = NULL;
VARIANT vT2;
VariantInit(&vT2);
LPWSTR lpValue = NULL;
hr = GetVariantFromArray(psaArray, i, VT_BSTR, vT2);
lpValue = GetStr(vT2);
CDeleteMe <wchar_t> r (lpValue);
VariantClear(&vT2);
hr = CustomGetMapping(pConn, pScope, lpValue, &pMapping2);
CReleaseMe r3 (pMapping2);
if (SUCCEEDED(hr))
hr = AddObjToStruct(pMapping2, &pProps, dwNumProps, &dwNumProps);
}
}
// Form the SQL statement.
hr = GetSelectClause(pSQL, pProps, dwNumProps);
wchar_t wTemp[1024];
if (SUCCEEDED(hr))
{
hr = GetFromClause(wTemp, pMappingObj, pProps, dwNumProps);
if (SUCCEEDED(hr))
{
wcscat(pSQL, wTemp);
hr = GetWhereClause(wTemp, pMappingObj, pClassObj, pPath, pProps, dwNumProps);
if (SUCCEEDED(hr))
wcscat(pSQL, wTemp);
}
}
if (SUCCEEDED(hr))
{
IRowset *pRowset = NULL;
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(), pSQL, &pRowset, NULL);
CReleaseMe r (pRowset);
if (SUCCEEDED(hr))
hr = CustomSetProperties(pScope, pRowset, m_pIMalloc, pClassObj,
pProps, dwNumProps, pObj);
}
ClearPropArray(pProps, dwNumProps);
}
}
}
}
if (SUCCEEDED(hr))
{
if (m_pController)
((CWmiDbController *)m_pController)->IncrementHitCount(false);
// Cache this object if needed.
if (GetObjectCache()->ObjectExists(dObjId) ||
(dwRequestedHandleType & 0xF00) == WMIDB_HANDLE_TYPE_WEAK_CACHE ||
(dwRequestedHandleType & 0xF00) == WMIDB_HANDLE_TYPE_STRONG_CACHE)
{
bool bCacheType = ((dwRequestedHandleType & 0xF00) == WMIDB_HANDLE_TYPE_STRONG_CACHE) ? 1 : 0;
GetObjectCache()->PutObject(dObjId, dClassId,
((CWmiDbHandle *)pScope)->m_dObjectId, lpKeyString, bCacheType, pObj);
}
}
if (FAILED(hr))
{
*ppResult = NULL;
pObj->Release();
}
}
GetSQLCache()->ReleaseConnection(pConn);
}
}
}
}
if (hr == WBEM_S_NO_ERROR && pObj)
{
// Wrap this in an IWmiDbHandle
CWmiDbHandle *pTemp = new CWmiDbHandle;
if (pTemp)
{
bool bImmediate = !(dwRequestedHandleType & WMIDB_HANDLE_TYPE_SUBSCOPED);
DWORD dwVersion = 0;
pTemp->m_pSession = this;
hr = VerifyObjectSecurity(NULL, dObjId, dClassId, ((CWmiDbHandle *)pScope)->m_dObjectId, 0, WBEM_ENABLE);
if (SUCCEEDED(hr))
{
hr = ((CWmiDbController *)m_pController)->LockCache.AddLock(bImmediate, dObjId, dwRequestedHandleType, pTemp,
((CWmiDbHandle *)pScope)->m_dObjectId, dClassId,
&((CWmiDbController *)m_pController)->SchemaCache, false, 0, 0, &dwVersion);
if (SUCCEEDED(hr))
{
((CWmiDbController *)m_pController)->AddHandle();
pTemp->AddRef();
pTemp->m_dwHandleType = dwRequestedHandleType;
pTemp->m_dObjectId = dObjId;
pTemp->m_bDefault = FALSE;
pTemp->m_dClassId = dClassId;
pTemp->m_dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
pTemp->m_dwVersion = dwVersion;
pTemp->m_pData = pObj;
pObj->AddRef();
if (ppResult)
*ppResult = pTemp;
}
}
if (FAILED(hr))
{
delete pTemp;
*ppResult = NULL;
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CustomGetMapping
//
//***************************************************************************
HRESULT CWmiDbSession::CustomGetMapping(CSQLConnection *pConn, IWmiDbHandle *pScope, LPWSTR lpClassName,
IWbemClassObject **ppMapping)
{
HRESULT hr = WBEM_S_NO_ERROR;
wchar_t *wTemp = new wchar_t [wcslen(lpClassName) + 50];
if (!wTemp)
return WBEM_E_OUT_OF_MEMORY;
CDeleteMe <wchar_t> d (wTemp);
swprintf(wTemp, L"__CustRepDrvrMapping.sClassName=\"%s\"", lpClassName);
IWmiDbHandle *pMapping = NULL;
LPWSTR lpPath = NULL;
hr = NormalizeObjectPath(pScope, wTemp, &lpPath, FALSE, NULL, NULL, pConn);
if (SUCCEEDED(hr))
{
CDeleteMe <wchar_t> d (lpPath);
SQL_ID dScopeId = 0;
hr = GetObject_Internal(lpPath, 0, WMIDB_HANDLE_TYPE_STRONG_CACHE|WMIDB_HANDLE_TYPE_VERSIONED, &dScopeId,
&pMapping, pConn);
CReleaseMe r (pMapping);
if (SUCCEEDED(hr))
{
IWbemClassObject *pMappingObj = NULL;
hr = pMapping->QueryInterface(IID_IWbemClassObject, (void **)&pMappingObj);
if (SUCCEEDED(hr))
*ppMapping = pMappingObj;
}
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CustomCreateMapping
//
//***************************************************************************
HRESULT CWmiDbSession::CustomCreateMapping(CSQLConnection *pConn, LPWSTR lpClassName, IWbemClassObject *pObj,
IWmiDbHandle *pScope)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemClassObject *pMapping = NULL;
hr = CustomGetMapping(pConn, pScope, lpClassName, &pMapping);
CReleaseMe r (pMapping);
if (FAILED(hr))
{
// If there's no mapping, this may be an abstract class.
IWbemQualifierSet *pQS = NULL;
pObj->GetQualifierSet(&pQS);
CReleaseMe r (pQS);
DWORD dwFlag = GetQualifierFlag(L"Abstract", pQS) ? REPDRVR_FLAG_ABSTRACT : 0;
if (dwFlag != 0)
hr = WBEM_S_NO_ERROR;
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CustomPutInstance
//
//***************************************************************************
HRESULT CWmiDbSession::CustomPutInstance(CSQLConnection *pConn, IWmiDbHandle *pScope, SQL_ID dClassId,
DWORD dwFlags, IWbemClassObject **ppObjToPut, LPWSTR lpClass)
{
HRESULT hr = WBEM_S_NO_ERROR;
IWbemClassObject *pObj = *ppObjToPut;
wchar_t wKeyhole[50];
LPWSTR lpTableName = NULL;
IWbemClassObject *pMapping = NULL;
LPWSTR lpClassName = GetPropertyVal(L"__Class", pObj);
CDeleteMe <wchar_t> d1 (lpClassName);
if (!lpClass)
hr = CustomGetMapping(pConn, pScope, lpClassName, &pMapping);
else
hr = CustomGetMapping(pConn, pScope, lpClass, &pMapping);
CReleaseMe r2 (pMapping);
if (SUCCEEDED(hr))
{
MappedProperties *pProps = NULL;
DWORD dwNumProps = 0;
BOOL bExists = FALSE;
BOOL bKeyhole = FALSE;
hr = ConvertObjToStruct(pMapping, &pProps, &dwNumProps);
CDeleteMe <MappedProperties> d3 (pProps);
if (SUCCEEDED(hr))
{
// Take the flags into account. See if the object already exists.
// If so (and not in violation of flags), update
// If not (and not in violation of flags), insert
// Special treatment for other tables.
LPWSTR lpRelPath = GetPropertyVal(L"__RelPath", pObj);
CDeleteMe <wchar_t> d3 (lpRelPath);
IWbemPath *pParser = NULL;
hr = CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER,
IID_IWbemPath, (LPVOID *) &pParser);
if (SUCCEEDED(hr))
{
pParser->SetText(WBEMPATH_CREATE_ACCEPT_ALL, lpRelPath);
CReleaseMe r (pParser);
IWmiDbHandle *pHandle = NULL;
hr = GetObject(pScope, pParser, 0, WMIDB_HANDLE_TYPE_VERSIONED, &pHandle);
if (SUCCEEDED(hr))
bExists = TRUE;
hr = 0;
CReleaseMe r1 (pHandle);
switch(dwFlags)
{
case WBEM_FLAG_CREATE_ONLY:
if (bExists)
hr = WBEM_E_ALREADY_EXISTS;
break;
case WBEM_FLAG_UPDATE_ONLY:
if (!bExists)
hr = WBEM_E_NOT_FOUND;
break;
default:
break;
}
if (SUCCEEDED(hr))
{
wchar_t wSQL[4096];
lpTableName = GetPropertyVal(L"sTableName", pMapping);
if (!lpTableName)
hr = WBEM_E_INVALID_OBJECT;
else
{
if (bExists)
hr = GetUpdateClause(wSQL, pMapping, pObj, pProps, dwNumProps, lpTableName);
else
hr = GetInsertClause(wSQL, pMapping, pObj, pProps, dwNumProps, &bKeyhole, lpTableName);
if (SUCCEEDED(hr))
{
IRowset *pRowset = NULL;
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(), wSQL, &pRowset);
CReleaseMe r (pRowset);
if (SUCCEEDED(hr))
{
if (bKeyhole)
{
// Grab the new GUID and stick it in the keyhole.
_bstr_t sKeyholeProp;
DWORD dwKeyholePropID = 0;
GetSchemaCache()->GetKeyholeProperty
(dClassId, dwKeyholePropID, sKeyholeProp);
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
CIMTYPE ct = 0;
pObj->Get(sKeyholeProp, 0, NULL, &ct, NULL);
hr = CSQLExecute::GetColumnValue(pRowset, 1, m_pIMalloc, &pRow, vTemp);
if (SUCCEEDED(hr) && sKeyholeProp.length())
pObj->Put(sKeyholeProp, 0, &vTemp, ct);
// Store this value for later use.
wcscpy(wKeyhole, vTemp.bstrVal);
pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
}
else
wcscpy(wKeyhole, L"");
}
}
}
}
}
}
// At this point, we have inserted the base table, and wKeyhole
// now contains the new ID.
// Insert or update all other tables, and blobs, as needed.
// ===========================================================
if (SUCCEEDED(hr))
{
for (int i = 0; i < dwNumProps; i++)
{
CWStringArray arrTables;
if ((pProps[i].wTableName && wcslen(pProps[i].wTableName)) || pProps[i].bStoreAsBlob)
{
wchar_t wSQL[4096];
BOOL bFound = FALSE;
if (!pProps[i].wTableName || !wcslen(pProps[i].wTableName))
{
delete pProps[i].wTableName;
pProps[i].wTableName = new wchar_t [ wcslen(lpTableName) + 1];
if (pProps[i].wTableName)
wcscpy(pProps[i].wTableName, lpTableName);
else
return WBEM_E_OUT_OF_MEMORY;
}
for (int j = 0; j < arrTables.Size(); j++)
{
if (!_wcsicmp(arrTables.GetAt(j), pProps[i].wTableName))
{
bFound = TRUE;
break;
}
}
if (!bFound)
arrTables.Add(pProps[i].wTableName);
else if (!pProps[i].bStoreAsBlob)
continue;
// Decomposition on Put
// Locate the matching classes, memcmp and insert new if needed
// Obtain new foreign keys, insert them and update ClassId, InstanceId
// GetPutClause will fail since we expect the base table to be the
// parent table, and in the special decomposition case, it will be the opposite.
if (pProps[i].bDecompose)
{
BYTE *pClassBuff = NULL, *pInstBuff = NULL;
DWORD dwClassBuffLen = 0, dwInstBuffLen = 0;
VARIANT vTemp;
VariantClear(&vTemp);
CIMTYPE ct = 0;
hr = pObj->Get(pProps[i].wPropName, 0, &vTemp, &ct, NULL);
if (SUCCEEDED(hr) && vTemp.vt == VT_UNKNOWN)
{
_IWmiObject *pInt = NULL;
IUnknown *pUnk = V_UNKNOWN(&vTemp);
hr = pUnk->QueryInterface(IID__IWmiObject, (void **)&pInt);
if (SUCCEEDED(hr))
{
CReleaseMe r (pInt);
LPWSTR lpClassName = GetPropertyVal(L"__Class", pInt);
LPWSTR lpTable = GetPropertyVal(L"sTableName", pMapping);
LPWSTR lpDatabase = GetPropertyVal(L"sDatabaseName", pMapping);
CDeleteMe <wchar_t> d1 (lpDatabase), d2 (lpTable), d3(lpClassName);
pInt->GetObjectParts(NULL, 0, WBEM_OBJ_INSTANCE_PART|WBEM_OBJ_DECORATION_PART, &dwInstBuffLen);
if (dwInstBuffLen)
{
pInstBuff = new BYTE[dwInstBuffLen];
if (pInstBuff)
hr = pInt->GetObjectParts(pInstBuff, dwInstBuffLen,
WBEM_OBJ_INSTANCE_PART|WBEM_OBJ_DECORATION_PART, &dwInstBuffLen);
else
return WBEM_E_OUT_OF_MEMORY;
}
pInt->GetObjectParts(NULL, 0, WBEM_OBJ_CLASS_PART, &dwClassBuffLen);
if (dwClassBuffLen)
{
pClassBuff = new BYTE[dwClassBuffLen];
if (pClassBuff)
hr = pInt->GetObjectParts(pClassBuff, dwClassBuffLen,
WBEM_OBJ_CLASS_PART, &dwClassBuffLen);
else
return WBEM_E_OUT_OF_MEMORY;
}
DWORD dwInstanceID = 0, dwClassID = 0;
wchar_t wWhere[1024];
GetWhereClause(wWhere, pMapping, pObj, pProps, dwNumProps);
LPWSTR lpBaseTable = FormatTableName(pMapping);
CDeleteMe <wchar_t> d4 (lpBaseTable);
// For existing instance, retrieve
// existing Instance Id
IRowset *pRowset = NULL;
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"select %s from %s %s", &pRowset, NULL,
pProps[i].arrForeignKeys[0], lpBaseTable, wWhere);
if (SUCCEEDED(hr))
{
CReleaseMe r (pRowset);
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
hr = CSQLExecute::GetColumnValue(pRowset, 1, m_pIMalloc, &pRow, vTemp);
hr = pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
pRow = NULL;
if (vTemp.vt == VT_I4)
dwInstanceID = vTemp.lVal;
else if (vTemp.vt == VT_BSTR)
dwInstanceID = _wtoi64(vTemp.bstrVal);
else
dwInstanceID = 0;
}
wchar_t wSQL[1024];
LPWSTR lpInstTable = FormatTableName(pMapping, pProps[i].wTableName);
CDeleteMe <wchar_t> d (lpInstTable);
if (!dwInstanceID)
{
swprintf(wSQL, L"insert into %s (%s) values (NULL) ",
lpInstTable, pProps[i].arrColumnNames[0]);
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(), wSQL);
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"select @@identity", &pRowset, NULL);
if (SUCCEEDED(hr))
{
CReleaseMe r (pRowset);
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
hr = CSQLExecute::GetColumnValue(pRowset, 1, m_pIMalloc, &pRow, vTemp);
hr = pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
pRow = NULL;
if (vTemp.vt == VT_I4)
dwInstanceID = vTemp.lVal;
else if (vTemp.vt == VT_BSTR)
dwInstanceID = _wtoi64(vTemp.bstrVal);
}
}
else
{
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"IF NOT EXISTS (select * from %s where %s = %ld) "
L" insert into %s (%s) values (NULL) ", NULL, NULL,
lpInstTable, pProps[i].arrColumnNames[0], dwInstanceID,
lpInstTable, pProps[i].arrColumnNames[0]);
}
swprintf(wSQL, L"select %s from %s where %s = %ld ",
pProps[i].arrColumnNames[0], lpInstTable,
pProps[i].arrForeignKeys[0], dwInstanceID);
hr = CSQLExecute::WriteImageValue(((COLEDBConnection *)pConn)->GetCommand(), wSQL, 1, pInstBuff, dwInstBuffLen);
// Obtain ID for class part. Find match
// or insert new and retrieve ID.
LPWSTR lpClassTable = FormatTableName(pMapping, pProps[i].wClassTable);
CDeleteMe <wchar_t> d5 (lpClassTable);
hr = GetClassBufferID (pConn, &pProps[i], lpClassTable, lpClassName,
pClassBuff, dwClassBuffLen, dwClassID, m_pIMalloc);
// Update main table with new Class + Instance IDs,
// if necessary.
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"update %s set %s = %ld, %s = %ld %s",NULL, NULL,
lpBaseTable, pProps[i].arrForeignKeys[0],
dwInstanceID, pProps[i].wClassForeignKey,
dwClassID, wWhere);
}
}
else
{
// Set both class and instance IDs to zero,
// and delete the instance row.
if (bExists)
{
wchar_t wWhere[1024];
GetWhereClause(wWhere, pMapping, pObj, pProps, dwNumProps);
LPWSTR lpBaseTable = FormatTableName(pMapping);
CDeleteMe <wchar_t> d2 (lpBaseTable);
IRowset *pRowset = NULL;
DWORD dInstanceId = 0;
// Need to retrieve existing Instance ID, if any.
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"select %s from %s %s", &pRowset, NULL,
pProps[i].arrForeignKeys[0], lpBaseTable, wWhere);
if (SUCCEEDED(hr))
{
CReleaseMe r (pRowset);
HROW *pRow = NULL;
VARIANT vTemp;
CClearMe c (&vTemp);
hr = CSQLExecute::GetColumnValue(pRowset, 1, m_pIMalloc, &pRow, vTemp);
hr = pRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
pRow = NULL;
if (vTemp.vt == VT_I4)
dInstanceId = vTemp.lVal;
}
if (dInstanceId)
{
LPWSTR lpTableName = FormatTableName(pMapping, pProps[i].wTableName);
CDeleteMe <wchar_t> d1 (lpTableName);
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"delete from %s where %s = %ld ",NULL, NULL, lpTableName,
pProps[i].arrForeignKeys[0], dInstanceId);
if (SUCCEEDED(hr))
{
// Update Existing IDs to zero
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(),
L"update %s set %s = 0, %s = 0 %s",NULL, NULL,
lpBaseTable, pProps[i].arrForeignKeys[0],
pProps[i].wClassForeignKey, wWhere);
}
}
}
}
}
else
{
// Where are the keys at this point?
// We need the key values
hr = GetPutClause (wSQL, pMapping, pObj,
pProps, dwNumProps, pProps[i].wTableName, wKeyhole, i);
if (SUCCEEDED(hr))
{
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(), wSQL);
if (SUCCEEDED(hr) && pProps[i].bStoreAsBlob)
{
wchar_t wTemp[512];
wchar_t wTable[128];
LPWSTR lpDatabase = GetPropertyVal(L"sDatabaseName", pMapping);
CDeleteMe <wchar_t> d1 (lpDatabase);
if (lpDatabase && wcslen(lpDatabase))
swprintf(wTable, L"%s..%s", lpDatabase, pProps[i].wTableName);
else
wcscpy(wTable, pProps[i].wTableName);
// Write any blob data if needed.
swprintf(wSQL, L"select %s from %s ", pProps[i].arrColumnNames[0], wTable);
GetWhereClause (wTemp, pMapping, pObj, pProps, dwNumProps);
wcscat(wSQL, wTemp);
BYTE *pBuff = NULL;
DWORD dwLen = 0;
VARIANT vTemp;
VariantInit(&vTemp);
CIMTYPE ct;
pObj->Get(pProps[i].wPropName, 0, &vTemp, &ct, NULL);
if (vTemp.vt != VT_NULL && vTemp.vt != VT_EMPTY)
{
if (ct == (CIM_FLAG_ARRAY + CIM_UINT8))
GetByteBuffer(&vTemp, &pBuff, dwLen);
else if (ct == CIM_OBJECT)
{
pBuff = NULL;
_IWmiObject *pInt = NULL;
IUnknown *pUnk = V_UNKNOWN(&vTemp);
hr = pUnk->QueryInterface(IID__IWmiObject, (void **)&pInt);
if (SUCCEEDED(hr))
{
pInt->GetObjectMemory(NULL, 0, &dwLen);
pBuff = new BYTE [dwLen];
if (pBuff)
{
DWORD dwLen1;
hr = pInt->GetObjectMemory(pBuff, dwLen, &dwLen1);
}
pInt->Release();
}
}
else if (ct == CIM_OBJECT + CIM_FLAG_ARRAY)
{
// We're going to have to extract each element
// from the array, concatenate the blobs, and
// store them separately.
hr = WBEM_E_NOT_SUPPORTED;
}
else
{
// We will only support storing text and
// uint8 arrays as blobs.
switch(ct)
{
case VT_BSTR:
pBuff = (BYTE *)vTemp.bstrVal;
dwLen = wcslen(vTemp.bstrVal) * 2;
break;
default:
hr = WBEM_E_NOT_SUPPORTED;
break;
}
}
if (SUCCEEDED(hr) && dwLen > 0)
hr = CSQLExecute::WriteImageValue(((COLEDBConnection *)pConn)->GetCommand(), wSQL, 1, pBuff, dwLen);
}
delete pBuff;
VariantClear(&vTemp);
}
}
}
}
}
}
ClearPropArray(pProps, dwNumProps);
}
delete lpTableName;
// Set data in the parent tables, if any.
if (SUCCEEDED(hr))
{
LPWSTR lpParent = NULL;
lpParent = GetPropertyVal(L"__SuperClass", pObj);
CDeleteMe <wchar_t> d2 (lpParent);
if (lpParent && wcslen(lpParent) && _wcsicmp(lpParent, L"__Class"))
CustomPutInstance(pConn, pScope, dClassId, dwFlags, ppObjToPut, lpParent);
}
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CustomDelete
//
//***************************************************************************
HRESULT CWmiDbSession::CustomDelete(CSQLConnection *pConn, IWmiDbHandle *pScope, IWmiDbHandle *pHandle, LPWSTR lpClass)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (((CWmiDbHandle *)pHandle)->m_dClassId == 1 ||
(lpClass && lpClass[0] == L'_'))
return WBEM_S_NO_ERROR; // Ignore classes and system objects.
IWbemClassObject *pObj = NULL, *pMapping = NULL;
hr = pHandle->QueryInterface(IID_IWbemClassObject, (void **)&pObj);
CReleaseMe r1 (pObj);
if (SUCCEEDED(hr))
{
LPWSTR lpClassName = NULL;
lpClassName = GetPropertyVal(L"__Class", pObj);
CDeleteMe <wchar_t> d1 (lpClassName);
if (!lpClass)
hr = CustomGetMapping(pConn, pScope, lpClassName, &pMapping);
else
hr = CustomGetMapping(pConn, pScope, lpClass, &pMapping);
CReleaseMe r2 (pMapping);
if (SUCCEEDED(hr))
{
// Just bind key properties
// and execute.
MappedProperties *pProps = NULL;
DWORD dwNumProps;
hr = ConvertObjToStruct(pMapping, &pProps, &dwNumProps);
CDeleteMe <MappedProperties> p (pProps);
if (SUCCEEDED(hr))
{
// If decomposition, only instance part will be deleted (not class)
wchar_t wSQL[2048];
hr = GetDeleteClause(wSQL, pMapping, pObj, pProps, dwNumProps);
if (SUCCEEDED(hr))
hr = CSQLExecute::ExecuteQuery(((COLEDBConnection *)pConn)->GetCommand(), wSQL);
ClearPropArray(pProps, dwNumProps);
}
// Clean up the parent tables, if any.
if (SUCCEEDED(hr))
{
LPWSTR lpParent = NULL;
lpParent = GetPropertyVal(L"__SuperClass", pObj);
CDeleteMe <wchar_t> d2 (lpParent);
if (lpParent && wcslen(lpParent) && _wcsicmp(lpParent, L"__Class"))
hr = CustomDelete(pConn, pScope, pHandle, lpParent);
}
}
// This may be an abstract class,
// or otherwise have no mapping.
else if (hr == WBEM_E_NOT_FOUND)
hr = WBEM_S_NO_ERROR;
}
return hr;
}
//***************************************************************************
//
// FormatWhereClause
//
//***************************************************************************
HRESULT FormatWhereClause (SWQLNode_RelExpr *pNode, _bstr_t &sSQL, MappedProperties *pMapping, DWORD dwNumProps)
{
HRESULT hr = WBEM_S_NO_ERROR;
if (pNode)
{
DWORD dwType = pNode->m_dwExprType;
_bstr_t sTemp;
switch(dwType)
{
case WQL_TOK_OR:
case WQL_TOK_AND:
if (pNode->m_pLeft)
{
sTemp = "(";
hr = FormatWhereClause((SWQLNode_RelExpr *)pNode->m_pLeft, sTemp, pMapping, dwNumProps);
}
if (dwType == WQL_TOK_OR)
sTemp += " OR ";
else
sTemp += " AND ";
if (pNode->m_pRight)
{
hr = FormatWhereClause((SWQLNode_RelExpr *)pNode->m_pRight, sTemp, pMapping, dwNumProps);
sTemp += ")";
}
sSQL += sTemp;
break;
case WQL_TOK_NOT:
sSQL += " NOT ";
// Supposedly, only a left clause follows not...
if (pNode->m_pLeft)
{
hr = FormatWhereClause((SWQLNode_RelExpr *)pNode->m_pLeft, sTemp, pMapping, dwNumProps);
sSQL += sTemp;
}
break;
default: // Typed expression
SWQLTypedExpr *pExpr = ((SWQLNode_RelExpr *)pNode)->m_pTypedExpr;
if (pExpr != NULL)
{
DWORD dwOp = pExpr->m_dwRelOperator;
wchar_t wSQL[1024];
BOOL bQueriable = FALSE;
LPWSTR lpColName = GetColumnName(pExpr->m_pColRef, pMapping, dwNumProps, &bQueriable, pExpr->m_pIntrinsicFuncOnColRef,
pExpr->m_pLeftFunction);
CDeleteMe <wchar_t> d2 (lpColName);
if (!lpColName || !bQueriable)
{
hr = WBEM_E_INVALID_QUERY;
break;
}
LPWSTR lpOp = GetOperator(dwOp);
LPWSTR lpValue = NULL;
CDeleteMe <wchar_t> d (lpOp);
switch (dwOp)
{
case WQL_TOK_NULL:
case WQL_TOK_ISNULL:
swprintf(wSQL, L" %s is null ", lpColName);
sSQL += wSQL;
break;
case WQL_TOK_NOT_NULL:
swprintf(wSQL, L" %s is not null ", lpColName);
sSQL += wSQL;
break;
case WQL_TOK_NOT_IN:
case WQL_TOK_IN:
case WQL_TOK_IN_CONST_LIST:
case WQL_TOK_NOT_IN_CONST_LIST:
case WQL_TOK_ISA:
case WQL_TOK_BETWEEN:
case WQL_TOK_IN_SUBSELECT:
case WQL_TOK_NOT_IN_SUBSELECT:
hr = WBEM_E_NOT_SUPPORTED;
break;
default:
if (pExpr->m_pConstValue)
{
if (pExpr->m_pConstValue->m_dwType == VT_LPWSTR)
{
lpValue = new wchar_t [10 + wcslen(pExpr->m_pConstValue->m_Value.m_pString)];
if (lpValue)
{
swprintf(lpValue, L"'%s'", pExpr->m_pConstValue->m_Value.m_pString);
// Double percents, since ExecQuery fries this character.
LPWSTR lpNew = StripQuotes(lpValue, '%');
if (lpNew)
{
delete lpValue;
lpValue = lpNew;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
}
else if(pExpr->m_pConstValue->m_dwType == VT_NULL)
hr = WBEM_E_INVALID_QUERY;
else
{
lpValue = new wchar_t [20];
if (lpValue)
swprintf(lpValue, L"%ld", pExpr->m_pConstValue->m_Value.m_lValue);
else
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
if (pExpr->m_pJoinColRef)
{
lpValue = GetColumnName(pExpr->m_pJoinColRef, pMapping, dwNumProps, &bQueriable,
pExpr->m_pIntrinsicFuncOnJoinColRef, pExpr->m_pRightFunction);
if (!bQueriable || ! lpValue)
hr = WBEM_E_INVALID_QUERY;
}
}
if (SUCCEEDED(hr))
swprintf(wSQL, L" %s %s %s ", lpColName, lpOp, lpValue);
sSQL += wSQL;
delete lpValue;
break;
}
}
}
}
return hr;
}
//***************************************************************************
//
// GetClassFromNode
//
//***************************************************************************
HRESULT GetClassFromNode (SWQLNode *pNode, LPWSTR * lpClassName)
{
HRESULT hr = WBEM_S_NO_ERROR;
LPWSTR lpTableName = NULL;
switch(pNode->m_dwNodeType)
{
case TYPE_SWQLNode_TableRefs:
if (((SWQLNode_TableRefs *)pNode)->m_nSelectType == WQL_FLAG_COUNT)
return WBEM_E_PROVIDER_NOT_CAPABLE;
if (pNode->m_pRight != NULL)
{
if (pNode->m_pRight->m_pLeft->m_dwNodeType != TYPE_SWQLNode_TableRef)
hr = WBEM_E_PROVIDER_NOT_CAPABLE;
else
{
SWQLNode_TableRef *pRef = (SWQLNode_TableRef *)pNode->m_pRight->m_pLeft;
lpTableName = pRef->m_pTableName;
}
}
else
return WBEM_E_INVALID_SYNTAX;
break;
case TYPE_SWQLNode_TableRef:
if (pNode->m_dwNodeType != TYPE_SWQLNode_TableRef)
hr = WBEM_E_INVALID_SYNTAX;
else
lpTableName = ((SWQLNode_TableRef *)pNode)->m_pTableName;
break;
default:
return WBEM_E_NOT_SUPPORTED;
break;
}
*lpClassName = lpTableName;
return hr;
}
//***************************************************************************
//
// CWmiDbSession::CustomFormatSQL
//
//***************************************************************************
HRESULT CWmiDbSession::CustomFormatSQL(IWmiDbHandle *pScope, IWbemQuery *pQuery, _bstr_t &sSQL, SQL_ID *dClassId,
MappedProperties **ppMapping, DWORD *pwNumProps, BOOL *pCount)
{
HRESULT hr = WBEM_S_NO_ERROR;
MappedProperties *pProps = NULL;
DWORD dwNumProps = 0;
sSQL = "";
BOOL bCount = FALSE;
LPWSTR lpClassName = NULL;
IWbemClassObject *pMapping = NULL;
SQL_ID dScopeId = ((CWmiDbHandle *)pScope)->m_dObjectId;
if (pQuery)
{
SWQLNode *pRoot = NULL, *pTop = NULL;
pQuery->GetAnalysis(WMIQ_ANALYSIS_RESERVED, 0, (void **)&pTop);
if (pTop && pTop->m_pLeft)
{
pRoot = pTop->m_pLeft;
if (pRoot->m_pRight != NULL)
{
if (pRoot->m_pRight->m_pRight != NULL)
{
hr = WBEM_E_INVALID_QUERY;
}
}
if (pRoot->m_pLeft != NULL)
{
if (((SWQLNode_TableRefs *)pRoot->m_pLeft)->m_nSelectType & WQL_FLAG_COUNT)
bCount = TRUE;
hr = GetClassFromNode(pRoot->m_pLeft, &lpClassName);
}
// Get the mapping information
if (SUCCEEDED(hr))
{
CSQLConnection *pConn = NULL;
hr = GetSQLCache()->GetConnection(&pConn);
if (SUCCEEDED(hr))
{
hr = CustomGetMapping(pConn, pScope, lpClassName, &pMapping);
CReleaseMe r2 (pMapping);
if (SUCCEEDED(hr))
{
BOOL bNeedWhere = TRUE;
hr = ConvertObjToStruct(pMapping, &pProps, &dwNumProps);
// CDeleteMe <wchar_t> d1 (pProps); This is released by caller.
if (SUCCEEDED(hr))
{
VARIANT vTemp;
IWbemClassObject *pClassObj = NULL;
GetClassObject(pConn, *dClassId, &pClassObj);
CClearMe c (&vTemp);
hr = pClassObj->Get(L"__Derivation", 0, &vTemp, NULL, NULL);
SAFEARRAY *psaArray = V_ARRAY(&vTemp);
if (psaArray)
{
long lLBound, lUBound;
SafeArrayGetLBound(psaArray, 1, &lLBound);
SafeArrayGetUBound(psaArray, 1, &lUBound);
lUBound -= lLBound;
lUBound += 1;
for (int i = 0; i < lUBound; i++)
{
IWbemClassObject *pMapping2 = NULL;
VARIANT vT2;
VariantInit(&vT2);
LPWSTR lpValue = NULL;
hr = GetVariantFromArray(psaArray, i, VT_BSTR, vT2);
lpValue = GetStr(vT2);
CDeleteMe <wchar_t> r (lpValue);
VariantClear(&vT2);
hr = CustomGetMapping(pConn, pScope, lpValue, &pMapping2);
CReleaseMe r3 (pMapping2);
if (SUCCEEDED(hr))
hr = AddObjToStruct(pMapping2, &pProps, dwNumProps, &dwNumProps);
}
}
GetSQLCache()->ReleaseConnection(pConn, hr);
wchar_t wSQL[1024];
if (!bCount)
hr = GetSelectClause(wSQL, pProps, dwNumProps, pRoot->m_pLeft->m_pLeft);
else
wcscpy(wSQL, L"select count(*) __Count");
wchar_t wTemp[1024];
if (SUCCEEDED(hr))
{
hr = GetFromClause(wTemp, pMapping, pProps, dwNumProps);
if (SUCCEEDED(hr))
wcscat(wSQL, wTemp);
}
if (SUCCEEDED(hr))
sSQL = wSQL;
// Now we parse the where clause.
if (pRoot->m_pRight && pRoot->m_pRight->m_pLeft)
{
_bstr_t sNewSQL;
hr = FormatWhereClause((SWQLNode_RelExpr *)pRoot->m_pRight->m_pLeft, sNewSQL, pProps, dwNumProps);
if (SUCCEEDED(hr) && wcslen(sNewSQL))
{
sSQL += L" where ";
sSQL += sNewSQL;
}
}
if (pRoot->m_pRight && pRoot->m_pRight->m_pRight && pRoot->m_pRight->m_pRight->m_pRight)
{
SWQLNode_ColumnList *pList = (SWQLNode_ColumnList *)pRoot->m_pRight->m_pRight->m_pRight->m_pLeft;
_bstr_t sNewSQL;
hr = GetOrderByClause(pList, sNewSQL, pProps, dwNumProps);
if (SUCCEEDED(hr))
sSQL += sNewSQL;
}
}
}
}
}
}
else
hr = WBEM_E_INVALID_QUERY;
}
else
hr = WBEM_E_INVALID_QUERY;
if (SUCCEEDED(hr))
{
if (pCount)
*pCount = bCount;
*ppMapping = pProps;
*pwNumProps = dwNumProps;
}
else
ClearPropArray(pProps, dwNumProps);
return hr;
}
//***************************************************************************
//
// CWmiCustomDbIterator::CWmiCustomDbIterator
//
//***************************************************************************
CWmiCustomDbIterator::CWmiCustomDbIterator()
{
m_pStatus = NULL;
m_pRowset = NULL;
m_pSession = NULL;
m_pIMalloc = NULL;
m_pConn = NULL;
m_uRefCount = 0;
m_dwNumProps = 0;
m_pPropMapping = NULL;
}
//***************************************************************************
//
// CWmiCustomDbIterator::~CWmiCustomDbIterator
//
//***************************************************************************
CWmiCustomDbIterator::~CWmiCustomDbIterator()
{
Cancel(0);
if (m_pSession)
m_pSession->Release();
m_pSession = NULL;
if (m_pIMalloc)
m_pIMalloc->Release();
m_pIMalloc = NULL;
ClearPropArray(m_pPropMapping, m_dwNumProps);
}
//***************************************************************************
//
// CWmiCustomDbIterator::QueryInterface
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiCustomDbIterator::QueryInterface
(REFIID riid,
void __RPC_FAR *__RPC_FAR *ppvObject)
{
*ppvObject = 0;
if (IID_IUnknown==riid || IID_IWmiDbIterator==riid )
{
*ppvObject = (IWmiDbIterator *)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//***************************************************************************
//
// CWmiCustomDbIterator::AddRef
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiCustomDbIterator::AddRef()
{
InterlockedIncrement((LONG *) &m_uRefCount);
return m_uRefCount;
}
//***************************************************************************
//
// CWmiCustomDbIterator::Release
//
//***************************************************************************
ULONG STDMETHODCALLTYPE CWmiCustomDbIterator::Release()
{
ULONG uNewCount = InterlockedDecrement((LONG *) &m_uRefCount);
if (0 != uNewCount)
return uNewCount;
delete this;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CWmiCustomDbIterator::Cancel
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiCustomDbIterator::Cancel(
/* [in] */ DWORD dwFlags)
{
HRESULT hr = WBEM_S_NO_ERROR;
hr = CSQLExecute::CancelQuery(m_pStatus);
if (m_pStatus)
m_pStatus->Release();
m_pStatus = NULL;
if (m_pConn)
{
((CWmiDbController *)m_pSession->m_pController)->ConnCache.ReleaseConnection(m_pConn, hr);
m_pConn = NULL;
}
if (m_pRowset)
m_pRowset->Release();
m_pRowset = NULL;
return hr;
}
//***************************************************************************
//
// CWmiCustomDbIterator::NextBatch
//
//***************************************************************************
HRESULT STDMETHODCALLTYPE CWmiCustomDbIterator::NextBatch(
/* [in] */ DWORD dwNumRequested,
/* [in] */ DWORD dwTimeOutSeconds,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwRequestedHandleType,
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwNumReturned,
/* [iid_is][length_is][size_is][out] */ LPVOID __RPC_FAR *ppObjects)
{
HRESULT hr = WBEM_S_NO_ERROR, hrRet = WBEM_S_NO_ERROR;
bool bImmediate = !(dwRequestedHandleType & WMIDB_HANDLE_TYPE_SUBSCOPED);
if (!m_pStatus && !m_pRowset)
return WBEM_S_NO_MORE_DATA;
if (!m_pSession || !(m_pSession->m_pController) ||
((CWmiDbController *)m_pSession->m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
return WBEM_E_SHUTTING_DOWN;
if (!dwNumRequested || !ppObjects)
return WBEM_E_INVALID_PARAMETER;
if (dwRequestedHandleType == WMIDB_HANDLE_TYPE_INVALID)
return WBEM_E_INVALID_PARAMETER;
// FIXME: We need to create a readahead cache.
if (dwFlags & WMIDB_FLAG_LOOKAHEAD ||
(riid != IID_IWmiDbHandle &&
riid != IID_IWbemClassObject &&
riid != IID__IWmiObject))
/// UuidCompare(pIIDRequestedInterface, &IID_IWmiDbHandle, NULL) ||
// UuidCompare(pIIDRequestedInterface, &IID_IWbemClassObject, NULL))
return E_NOTIMPL;
// For each ObjectId, do we instantiate a new handle,
// and increment a background ref count on the object itself?
// How do we keep track of the handles that are in use??
try
{
HROW *pRow = NULL;
VARIANT vTemp;
VariantInit(&vTemp);
int iNumRetrieved = 0;
IRowset *pIRowset = NULL;
IWbemClassObject *pClassObj = NULL;
if (!m_bCount)
{
hr = ((CWmiDbController *)m_pSession->m_pController)->ObjectCache.GetObject(m_dClassId, &pClassObj);
if (FAILED(hr))
hr = m_pSession->GetClassObject(NULL, m_dClassId, &pClassObj);
}
else
{
hr = CoCreateInstance(CLSID_WbemClassObject, NULL, CLSCTX_INPROC_SERVER,
IID_IWbemClassObject, (void **)&pClassObj);
if (SUCCEEDED(hr))
{
VARIANT vTemp;
VariantInit(&vTemp);
vTemp.bstrVal = SysAllocString(L"__Generic");
vTemp.vt = VT_BSTR;
pClassObj->Put(L"__Class", 0, &vTemp, CIM_STRING);
VariantClear(&vTemp);
pClassObj->Put(L"Count", 0, NULL, CIM_UINT32);
}
}
CReleaseMe r (pClassObj);
if (m_pStatus)
{
hr = CSQLExecute::IsDataReady(m_pStatus);
// TO DO: Wait if we are pending. Fail for now.
if (SUCCEEDED(hr))
{
hr = m_pStatus->QueryInterface(IID_IRowset, (void **)&pIRowset);
}
}
else
pIRowset = m_pRowset;
if (SUCCEEDED(hr) && pIRowset)
{
// TO DO: Take the timeout value into consideration!!!
while (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA && iNumRetrieved < dwNumRequested)
{
if (!m_pSession || !(m_pSession->m_pController) ||
((CWmiDbController *)m_pSession->m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
{
hrRet = WBEM_E_SHUTTING_DOWN;
break;
}
IWbemClassObject *pNew = NULL;
hr = pClassObj->SpawnInstance(0, &pNew);
if (SUCCEEDED(hr))
{
if (m_bCount)
{
VARIANT vTemp;
CClearMe c (&vTemp);
hr = CSQLExecute::GetColumnValue(pIRowset, 1, m_pIMalloc, &pRow, vTemp);
pNew->Put(L"Count", 0, &vTemp, CIM_UINT32);
}
else
{
hr = ((CWmiDbSession *)m_pSession)->CustomSetProperties(m_pScope, pIRowset, m_pIMalloc, pClassObj, m_pPropMapping, m_dwNumProps, pNew);
if (FAILED(hr))
break;
}
}
else
break;
// Generate the hash value from the key string.
SQL_ID dID = 0;
LPWSTR lpPath = GetPropertyVal(L"__RelPath", pNew);
LPWSTR lpKey = GetKeyString(lpPath);
CDeleteMe <wchar_t> d1 (lpPath), d2 (lpKey);
dID = CRC64::GenerateHashValue(lpKey);
hr = ((CWmiDbSession *)m_pSession)->VerifyObjectSecurity(NULL, dID, m_dClassId, m_dwScopeId, 0, WBEM_ENABLE);
if (SUCCEEDED(hr))
{
if (riid == IID_IWbemClassObject ||
riid == IID__IWmiObject)
{
ppObjects[iNumRetrieved] = pNew;
}
else
{
CWmiDbHandle *pTemp = new CWmiDbHandle;
if (pTemp)
{
DWORD dwVersion = 0;
// Obtain a lock for this object
// =============================
pTemp->m_pSession = m_pSession;
hr = ((CWmiDbController *)m_pSession->m_pController)->LockCache.AddLock(bImmediate, dID, dwRequestedHandleType, pTemp,
m_dwScopeId, m_dClassId, &((CWmiDbController *)m_pSession->m_pController)->SchemaCache, false,
0, 0, &dwVersion);
if (FAILED(hr))
{
delete pTemp;
// If they failed to get a handle, what do we do?
// Ignore it and continue, I guess.
hrRet = WBEM_S_PARTIAL_RESULTS;
ppObjects[iNumRetrieved] = NULL;
}
else
{
((CWmiDbController *)m_pSession->m_pController)->AddHandle();
pTemp->AddRef();
pTemp->m_dwVersion = dwVersion;
pTemp->m_dwHandleType = dwRequestedHandleType;
pTemp->m_dClassId = m_dClassId;
pTemp->m_dObjectId = dID;
pTemp->m_pData = pNew;
pTemp->m_bDefault = FALSE;
pTemp->m_dScopeId = m_dwScopeId;
ppObjects[iNumRetrieved] = pTemp;
}
}
else
{
// *pQueryResult = NULL; // What do we do here? Cancel, I assume.
hrRet = WBEM_E_OUT_OF_MEMORY;
break;
}
}
iNumRetrieved++;
}
else
hrRet = WBEM_S_PARTIAL_RESULTS;
if (m_pSession && ((CWmiDbSession *)m_pSession)->m_pController)
((CWmiDbController *)m_pSession->m_pController)->IncrementHitCount(false);
VariantClear(&vTemp);
hr = pIRowset->ReleaseRows(1, pRow, NULL, NULL, NULL);
delete pRow;
pRow = NULL;
if (m_bCount)
{
hr = WBEM_S_NO_MORE_DATA;
break;
}
if (iNumRetrieved == dwNumRequested)
break;
hr = CSQLExecute::GetColumnValue(pIRowset, 1, m_pIMalloc, &pRow, vTemp);
}
}
// Null out m_pStatus if there are no more results!!!
if (hr == WBEM_S_NO_MORE_DATA)
{
hrRet = WBEM_S_NO_MORE_DATA;
Cancel(0);
}
if (pdwNumReturned)
*pdwNumReturned = iNumRetrieved;
}
catch (...)
{
hrRet = WBEM_E_CRITICAL_ERROR;
}
return hrRet;
}