821 lines
22 KiB
C++
821 lines
22 KiB
C++
/*++
|
|
|
|
Copyright (C) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
PROTOQ.CPP
|
|
|
|
Abstract:
|
|
|
|
Prototype query support for WinMgmt Query Engine.
|
|
This was split out from QENGINE.CPP for better source
|
|
organization.
|
|
|
|
History:
|
|
|
|
raymcc 04-Jul-99 Created.
|
|
raymcc 14-Aug-99 Resubmit due to VSS problem.
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <wbemcore.h>
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// Local defs
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
static HRESULT SelectColForClass(
|
|
IN CWQLScanner & Parser,
|
|
IN CFlexArray *pClassDefs,
|
|
IN SWQLColRef *pColRef,
|
|
IN int & nPosition
|
|
);
|
|
|
|
static HRESULT AdjustClassDefs(
|
|
IN CFlexArray *pClassDefs,
|
|
OUT IWbemClassObject **pRetNewClass
|
|
);
|
|
|
|
static HRESULT GetUnaryPrototype(
|
|
IN CWQLScanner & Parser,
|
|
IN LPWSTR pszClass,
|
|
IN LPWSTR pszAlias,
|
|
IN CWbemNamespace *pNs,
|
|
IN IWbemContext *pContext,
|
|
IN CBasicObjectSink *pSink
|
|
);
|
|
|
|
static HRESULT RetrieveClassDefs(
|
|
IN CWQLScanner & Parser,
|
|
IN CWbemNamespace *pNs,
|
|
IN IWbemContext *pContext,
|
|
IN CWStringArray & aAliasNames,
|
|
OUT CFlexArray *pDefs
|
|
);
|
|
|
|
static HRESULT ReleaseClassDefs(
|
|
IN CFlexArray *pDefs
|
|
);
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// ExecPrototypeQuery
|
|
//
|
|
// Called by CQueryEngine::ExecQuery for SMS-style prototypes.
|
|
//
|
|
// Executes the query and returns only the class definition implied
|
|
// by the query, whether a join or a simple class def.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT ExecPrototypeQuery(
|
|
IN CWbemNamespace *pNs,
|
|
IN LPWSTR pszQuery,
|
|
IN IWbemContext* pContext,
|
|
IN CBasicObjectSink *pSink
|
|
)
|
|
{
|
|
HRESULT hRes;
|
|
int nRes;
|
|
CFlexArray aClassDefs;
|
|
int i;
|
|
|
|
if (pNs == NULL || pszQuery == NULL || wcslen(pszQuery) == 0 ||
|
|
pSink == NULL)
|
|
return pSink->Return(WBEM_E_INVALID_PARAMETER);
|
|
|
|
// Parse the query and determine if it is a single class.
|
|
// ======================================================
|
|
|
|
CTextLexSource src(pszQuery);
|
|
CWQLScanner Parser(&src);
|
|
nRes = Parser.Parse();
|
|
if (nRes != CWQLScanner::SUCCESS)
|
|
return pSink->Return(WBEM_E_INVALID_QUERY);
|
|
|
|
// If a single class definition, branch, since we don't
|
|
// want to create a __GENERIC object.
|
|
// ====================================================
|
|
|
|
CWStringArray aAliases;
|
|
Parser.GetReferencedAliases(aAliases);
|
|
|
|
if (aAliases.Size() == 1)
|
|
{
|
|
LPWSTR pszClass = Parser.AliasToTable(aAliases[0]);
|
|
return GetUnaryPrototype(Parser, pszClass, aAliases[0], pNs, pContext, pSink);
|
|
}
|
|
|
|
// If here, a join must have occurred.
|
|
// ===================================
|
|
|
|
hRes = RetrieveClassDefs(
|
|
Parser,
|
|
pNs,
|
|
pContext,
|
|
aAliases,
|
|
&aClassDefs
|
|
);
|
|
|
|
if (hRes)
|
|
{
|
|
ReleaseClassDefs(&aClassDefs);
|
|
return pSink->Return(WBEM_E_INVALID_QUERY);
|
|
}
|
|
|
|
// Iterate through all the properties selected.
|
|
// ============================================
|
|
|
|
const CFlexArray *pSelCols = Parser.GetSelectedColumns();
|
|
|
|
if (pSelCols == 0)
|
|
{
|
|
ReleaseClassDefs(&aClassDefs);
|
|
return pSink->Return(WBEM_E_FAILED);
|
|
}
|
|
|
|
int nPosSoFar = 0;
|
|
for (i = 0; i < pSelCols->Size(); i++)
|
|
{
|
|
SWQLColRef *pColRef = (SWQLColRef *) pSelCols->GetAt(i);
|
|
hRes = SelectColForClass(Parser, &aClassDefs, pColRef, nPosSoFar);
|
|
|
|
if (hRes)
|
|
{
|
|
ReleaseClassDefs(&aClassDefs);
|
|
return pSink->Return(hRes);
|
|
}
|
|
}
|
|
|
|
// If here, we have the class definitions.
|
|
// =======================================
|
|
|
|
IWbemClassObject *pProtoInst = 0;
|
|
AdjustClassDefs(&aClassDefs, &pProtoInst);
|
|
|
|
pSink->Add(pProtoInst);
|
|
pProtoInst->Release();
|
|
|
|
ReleaseClassDefs(&aClassDefs);
|
|
|
|
return pSink->Return(WBEM_NO_ERROR);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
struct SelectedClass
|
|
{
|
|
IWbemClassObject *m_pClassDef;
|
|
WString m_wsAlias;
|
|
WString m_wsClass;
|
|
CWStringArray m_aSelectedCols;
|
|
BOOL m_bAll;
|
|
CFlexArray m_aSelectedColsPos;
|
|
|
|
void SetNamed(LPWSTR pName, int & nPos)
|
|
{
|
|
m_aSelectedCols.Add(pName);
|
|
#ifdef _WIN64
|
|
m_aSelectedColsPos.Add(IntToPtr(nPos++)); // ok since we are really using safearray for dword
|
|
#else
|
|
m_aSelectedColsPos.Add((void *)nPos++);
|
|
#endif
|
|
};
|
|
|
|
void SetAll(int & nPos);
|
|
SelectedClass() { m_pClassDef = 0; m_bAll = FALSE; }
|
|
~SelectedClass() { if (m_pClassDef) m_pClassDef->Release(); }
|
|
};
|
|
|
|
|
|
void SelectedClass::SetAll(int & nPos)
|
|
{
|
|
m_bAll = TRUE;
|
|
|
|
// For each property, add an entry
|
|
|
|
CWbemClass *pCls = (CWbemClass *)m_pClassDef;
|
|
pCls->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
|
|
BSTR PropName;
|
|
while (S_OK == pCls->Next(0, &PropName, NULL, NULL, NULL))
|
|
{
|
|
SetNamed(PropName, nPos);
|
|
SysFreeString(PropName);
|
|
}
|
|
pCls->EndEnumeration();
|
|
|
|
};
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
static HRESULT RetrieveClassDefs(
|
|
IN CWQLScanner & Parser,
|
|
IN CWbemNamespace *pNs,
|
|
IN IWbemContext *pContext,
|
|
IN CWStringArray & aAliasNames,
|
|
OUT CFlexArray *pDefs
|
|
)
|
|
{
|
|
for (int i = 0; i < aAliasNames.Size(); i++)
|
|
{
|
|
// Retrieve the class definition.
|
|
// ==============================
|
|
|
|
IWbemClassObject *pClassDef = 0;
|
|
LPWSTR pszClass = Parser.AliasToTable(aAliasNames[i]);
|
|
if (pszClass == 0)
|
|
continue;
|
|
|
|
HRESULT hRes = pNs->Exec_GetObjectByPath(pszClass, 0, pContext,
|
|
&pClassDef, 0);
|
|
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
|
|
SelectedClass *pSelClass = new SelectedClass;
|
|
if (pSelClass == 0)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
pSelClass->m_pClassDef = pClassDef;
|
|
pSelClass->m_wsClass = pszClass;
|
|
pSelClass->m_wsAlias = aAliasNames[i];
|
|
|
|
pDefs->Add(pSelClass);
|
|
}
|
|
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
static HRESULT ReleaseClassDefs(
|
|
IN CFlexArray *pDefs
|
|
)
|
|
{
|
|
for (int i = pDefs->Size()-1; i >= 0 ; i--)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pDefs->GetAt(i);
|
|
delete pSelClass;
|
|
}
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
static HRESULT SelectColForClass(
|
|
IN CWQLScanner & Parser,
|
|
IN CFlexArray *pClassDefs,
|
|
IN SWQLColRef *pColRef,
|
|
IN int & nPosition
|
|
)
|
|
{
|
|
int i;
|
|
HRESULT hRes;
|
|
|
|
if (!pColRef)
|
|
return WBEM_E_FAILED;
|
|
|
|
// If the column reference contains the class referenced
|
|
// via an alias and there is no asterisk, we are all set.
|
|
// ======================================================
|
|
|
|
if (pColRef->m_pTableRef)
|
|
{
|
|
// We now have the class name. Let's find it and add
|
|
// the referenced column for that class!
|
|
// =================================================
|
|
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
|
|
if (wbem_wcsicmp(LPWSTR(pSelClass->m_wsAlias), pColRef->m_pTableRef) != 0)
|
|
continue;
|
|
|
|
CWbemClass *pCls = (CWbemClass *) pSelClass->m_pClassDef;
|
|
|
|
// See if the asterisk was used for this class.
|
|
// =============================================
|
|
|
|
if (pColRef->m_pColName[0] == L'*' && pColRef->m_pColName[1] == 0)
|
|
{
|
|
pSelClass->SetAll(nPosition);
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
// If here, a property was mentioned by name.
|
|
// Verify that it exists.
|
|
// ==========================================
|
|
|
|
CVar Prop;
|
|
hRes = pCls->GetProperty(pColRef->m_pColName, &Prop);
|
|
if (hRes)
|
|
return WBEM_E_INVALID_QUERY;
|
|
|
|
// Mark it as seleted.
|
|
// ===================
|
|
|
|
pSelClass->SetNamed(pColRef->m_pColName, nPosition);
|
|
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
// If here, we couldn't locate the property in any class.
|
|
// ======================================================
|
|
|
|
return WBEM_E_INVALID_QUERY;
|
|
}
|
|
|
|
|
|
// Did we select * from all tables?
|
|
// ================================
|
|
|
|
if (pColRef->m_dwFlags & WQL_FLAG_ASTERISK)
|
|
{
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
pSelClass->SetAll(nPosition);
|
|
}
|
|
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
|
|
// If here, we have an uncorrelated property and we have to find out
|
|
// which class it belongs to. If it belongs to more than one, we have
|
|
// an ambiguous query.
|
|
// ===================================================================
|
|
|
|
DWORD dwTotalMatches = 0;
|
|
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
CWbemClass *pCls = (CWbemClass *) pSelClass->m_pClassDef;
|
|
|
|
// Try to locate the property in this class.
|
|
// =========================================
|
|
|
|
CVar Prop;
|
|
hRes = pCls->GetProperty(pColRef->m_pColName, &Prop);
|
|
|
|
if (hRes == 0)
|
|
{
|
|
pSelClass->SetNamed(pColRef->m_pColName, nPosition);
|
|
dwTotalMatches++;
|
|
}
|
|
}
|
|
|
|
// If more than one match occurred, we have an ambiguous query.
|
|
// ============================================================
|
|
|
|
if (dwTotalMatches != 1)
|
|
return WBEM_E_INVALID_QUERY;
|
|
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT AddOrderQualifiers(
|
|
CWbemClass *pCls,
|
|
BSTR PropName,
|
|
CFlexArray Matches
|
|
)
|
|
{
|
|
IWbemQualifierSet * pQual;
|
|
SCODE sc = pCls->GetPropertyQualifierSet(PropName, &pQual);
|
|
if(sc != S_OK)
|
|
return sc;
|
|
|
|
|
|
// Create a safe array
|
|
|
|
SAFEARRAYBOUND aBounds[1];
|
|
aBounds[0].lLbound = 0;
|
|
aBounds[0].cElements = Matches.Size();
|
|
|
|
SAFEARRAY* pArray = SafeArrayCreate(VT_I4, 1, aBounds);
|
|
|
|
// Stuff the individual data pieces
|
|
// ================================
|
|
|
|
for(int nIndex = 0; nIndex < Matches.Size(); nIndex++)
|
|
{
|
|
long lPos = PtrToLong(Matches.GetAt(nIndex));
|
|
sc = SafeArrayPutElement(pArray, (long*)&nIndex, &lPos);
|
|
}
|
|
|
|
VARIANT var;
|
|
var.vt = VT_ARRAY | VT_I4;
|
|
var.parray = pArray;
|
|
|
|
BSTR Name = SysAllocString(L"Order");
|
|
if (Name == 0)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
sc = pQual->Put(Name, &var, 0);
|
|
SysFreeString(Name);
|
|
VariantClear(&var);
|
|
pQual->Release();
|
|
return sc;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT SetPropertyOrderQualifiers(
|
|
SelectedClass *pSelClass
|
|
)
|
|
{
|
|
|
|
|
|
CWbemClass *pCls = (CWbemClass *) pSelClass->m_pClassDef;
|
|
|
|
// Go through each property
|
|
|
|
pCls->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
|
|
BSTR PropName;
|
|
while (S_OK == pCls->Next(0, &PropName, NULL, NULL, NULL))
|
|
{
|
|
|
|
// Build up a list of properties that Match
|
|
|
|
CFlexArray Matches;
|
|
bool bAtLeastOne = false;
|
|
for(int iCnt = 0; iCnt < pSelClass->m_aSelectedCols.Size(); iCnt++)
|
|
if(!wbem_wcsicmp(pSelClass->m_aSelectedCols.GetAt(iCnt), PropName))
|
|
{
|
|
Matches.Add(pSelClass->m_aSelectedColsPos.GetAt(iCnt));
|
|
bAtLeastOne = true;
|
|
}
|
|
|
|
if(bAtLeastOne)
|
|
AddOrderQualifiers(pCls, PropName, Matches);
|
|
|
|
SysFreeString(PropName);
|
|
}
|
|
pCls->EndEnumeration();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// AdjustClassDefs
|
|
//
|
|
// After all class definitions have been retrieved, they are adjusted
|
|
// to only have the properties required and combined into a __GENERIC
|
|
// instance.
|
|
//
|
|
//***************************************************************************
|
|
|
|
static HRESULT AdjustClassDefs(
|
|
IN CFlexArray *pClassDefs,
|
|
OUT IWbemClassObject **pRetNewClass
|
|
)
|
|
{
|
|
int i;
|
|
HRESULT hRes;
|
|
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
CWbemClass *pCls = (CWbemClass *) pSelClass->m_pClassDef;
|
|
|
|
if (pSelClass->m_bAll)
|
|
{
|
|
SetPropertyOrderQualifiers(pSelClass);
|
|
continue;
|
|
}
|
|
|
|
WString wsError = pCls->FindLimitationError(0, &pSelClass->m_aSelectedCols);
|
|
|
|
if (wsError.Length() > 0)
|
|
return WBEM_E_FAILED;
|
|
|
|
// Map the limitaiton
|
|
// ==================
|
|
|
|
CLimitationMapping Map;
|
|
BOOL bValid = pCls->MapLimitation(0, &pSelClass->m_aSelectedCols, &Map);
|
|
|
|
if (!bValid)
|
|
return WBEM_E_FAILED;
|
|
|
|
CWbemClass* pStrippedClass = 0;
|
|
hRes = pCls->GetLimitedVersion(&Map, &pStrippedClass);
|
|
if(!FAILED(hRes))
|
|
{
|
|
pSelClass->m_pClassDef = pStrippedClass;
|
|
SetPropertyOrderQualifiers(pSelClass);
|
|
pCls->Release();
|
|
}
|
|
}
|
|
|
|
// Count the number of objects that actually have properties
|
|
|
|
int iNumObj = 0;
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
CWbemObject *pObj = (CWbemObject *) pSelClass->m_pClassDef;
|
|
if (pObj->GetNumProperties() > 0)
|
|
iNumObj++;
|
|
}
|
|
|
|
// If there is just one object with properties, return it rather than the generic object
|
|
|
|
if(iNumObj == 1)
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
CWbemObject *pObj = (CWbemObject *) pSelClass->m_pClassDef;
|
|
if (pObj->GetNumProperties() == 0)
|
|
continue;
|
|
// Return it.
|
|
// ==========
|
|
|
|
*pRetNewClass = pObj;
|
|
pObj->AddRef();
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
|
|
// Prepare a __GENERIC class def. We construct a dummy definition which
|
|
// has properties named for each of the aliases used in the query.
|
|
// =====================================================================
|
|
|
|
CGenericClass *pNewClass = new CGenericClass;
|
|
if (pNewClass == 0)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
pNewClass->Init();
|
|
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
CWbemObject *pObj = (CWbemObject *) pSelClass->m_pClassDef;
|
|
|
|
if (pObj->GetNumProperties() == 0)
|
|
continue;
|
|
|
|
CVar vEmbeddedClass;
|
|
vEmbeddedClass.SetAsNull();
|
|
|
|
pNewClass->SetPropValue(pSelClass->m_wsAlias, &vEmbeddedClass,
|
|
CIM_OBJECT);
|
|
|
|
CVar vClassName;
|
|
if (FAILED(pObj->GetClassName(&vClassName)))
|
|
throw CX_MemoryException();
|
|
|
|
WString wsCimType = L"object:";
|
|
wsCimType += vClassName.GetLPWSTR();
|
|
CVar vCimType(VT_BSTR, wsCimType);
|
|
|
|
pNewClass->SetPropQualifier(pSelClass->m_wsAlias, L"cimtype", 0,
|
|
&vCimType);
|
|
};
|
|
|
|
// Spawn an instance of this class.
|
|
// ================================
|
|
|
|
CWbemInstance* pProtoInst = 0;
|
|
pNewClass->SpawnInstance(0, (IWbemClassObject **) &pProtoInst);
|
|
pNewClass->Release();
|
|
|
|
// Now assign the properties to the embedded instances.
|
|
// ====================================================
|
|
|
|
for (i = 0; i < pClassDefs->Size(); i++)
|
|
{
|
|
SelectedClass *pSelClass = (SelectedClass *) pClassDefs->GetAt(i);
|
|
CWbemClass *pCls = (CWbemClass *) pSelClass->m_pClassDef;
|
|
|
|
if (pCls->GetNumProperties() == 0)
|
|
continue;
|
|
|
|
CVar vEmbedded;
|
|
vEmbedded.SetEmbeddedObject((IWbemClassObject *) pCls);
|
|
|
|
pProtoInst->SetPropValue(pSelClass->m_wsAlias, &vEmbedded, 0);
|
|
};
|
|
|
|
// Return it.
|
|
// ==========
|
|
|
|
*pRetNewClass = pProtoInst;
|
|
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
static HRESULT GetUnaryPrototype(
|
|
IN CWQLScanner & Parser,
|
|
IN LPWSTR pszClass,
|
|
IN LPWSTR pszAlias,
|
|
IN CWbemNamespace *pNs,
|
|
IN IWbemContext *pContext,
|
|
IN CBasicObjectSink *pSink
|
|
)
|
|
{
|
|
int i;
|
|
|
|
// Retrieve the class definition.
|
|
// ==============================
|
|
|
|
IWbemClassObject *pClassDef = 0;
|
|
IWbemClassObject *pErrorObj = 0;
|
|
|
|
HRESULT hRes = pNs->Exec_GetObjectByPath(pszClass, 0, pContext,
|
|
&pClassDef, &pErrorObj);
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
pSink->SetStatus(0, hRes, NULL, pErrorObj);
|
|
if (pErrorObj)
|
|
pErrorObj->Release();
|
|
return S_OK;
|
|
}
|
|
|
|
if (pErrorObj)
|
|
pErrorObj->Release();
|
|
|
|
CWbemClass *pCls = (CWbemClass *) pClassDef;
|
|
BOOL bKeepAll = FALSE;
|
|
|
|
// This keeps track of the order in which columns are selected
|
|
|
|
SelectedClass sel;
|
|
int nPosition = 0;
|
|
sel.m_pClassDef = pClassDef;
|
|
pClassDef->AddRef();
|
|
sel.m_wsClass = pszClass;
|
|
|
|
// Go through all the columns and make sure that the properties are valid
|
|
// ======================================================================
|
|
|
|
const CFlexArray *pSelCols = Parser.GetSelectedColumns();
|
|
if (pSelCols == 0)
|
|
return pSink->Return(WBEM_E_FAILED);
|
|
|
|
for (i = 0; i < pSelCols->Size(); i++)
|
|
{
|
|
SWQLColRef *pColRef = (SWQLColRef *) pSelCols->GetAt(i);
|
|
|
|
if (pColRef->m_dwFlags & WQL_FLAG_ASTERISK)
|
|
{
|
|
bKeepAll = TRUE;
|
|
sel.SetAll(nPosition);
|
|
continue;
|
|
}
|
|
|
|
if (pColRef->m_pColName)
|
|
{
|
|
|
|
// check for the "select x.* from x" case
|
|
|
|
if(pColRef->m_pColName[0] == L'*' && pColRef->m_pColName[1] == 0)
|
|
{
|
|
if (!_wcsicmp(pColRef->m_pTableRef, pszAlias))
|
|
{
|
|
bKeepAll = TRUE;
|
|
sel.SetAll(nPosition);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
return pSink->Return(WBEM_E_INVALID_QUERY);
|
|
}
|
|
}
|
|
|
|
// Verify that the class has it
|
|
// ============================
|
|
|
|
CIMTYPE ct;
|
|
if(FAILED(pCls->GetPropertyType(pColRef->m_pColName, &ct)))
|
|
{
|
|
// No such property
|
|
// ================
|
|
|
|
return pSink->Return(WBEM_E_INVALID_QUERY);
|
|
}
|
|
sel.SetNamed(pColRef->m_pColName, nPosition);
|
|
}
|
|
}
|
|
|
|
// Eliminate unreferenced columns from the query.
|
|
// ==============================================
|
|
|
|
CWStringArray aPropsToKeep;
|
|
|
|
if(!bKeepAll)
|
|
{
|
|
// Move through each property in the class and
|
|
// see if it is referenced. If not, remove it.
|
|
// ============================================
|
|
|
|
int nNumProps = pCls->GetNumProperties();
|
|
for (i = 0; i < nNumProps; i++)
|
|
{
|
|
CVar Prop;
|
|
pCls->GetPropName(i, &Prop);
|
|
|
|
// See if this name is used in the query.
|
|
// ======================================
|
|
|
|
for (int i2 = 0; i2 < pSelCols->Size(); i2++)
|
|
{
|
|
SWQLColRef *pColRef = (SWQLColRef *) pSelCols->GetAt(i2);
|
|
|
|
if (pColRef->m_pColName && wbem_wcsicmp(Prop,
|
|
pColRef->m_pColName) == 0)
|
|
{
|
|
aPropsToKeep.Add((LPWSTR) Prop);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now we have a list of properties to remove.
|
|
// ===========================================
|
|
|
|
if (!bKeepAll && aPropsToKeep.Size())
|
|
{
|
|
WString wsError = pCls->FindLimitationError(0, &aPropsToKeep);
|
|
|
|
if (wsError.Length() > 0)
|
|
{
|
|
pClassDef->Release();
|
|
return pSink->Return(WBEM_E_FAILED);
|
|
}
|
|
|
|
// Map the limitaiton
|
|
// ==================
|
|
|
|
CLimitationMapping Map;
|
|
BOOL bValid = pCls->MapLimitation(0, &aPropsToKeep, &Map);
|
|
|
|
if (!bValid)
|
|
{
|
|
pClassDef->Release();
|
|
return pSink->Return(WBEM_E_FAILED);
|
|
}
|
|
|
|
CWbemClass* pNewStrippedClass = 0;
|
|
hRes = pCls->GetLimitedVersion(&Map, &pNewStrippedClass);
|
|
if(!FAILED(hRes))
|
|
{
|
|
pClassDef->Release(); // Once for creation
|
|
pClassDef->Release(); // Once for for the copy in sel
|
|
pClassDef = pNewStrippedClass;
|
|
sel.m_pClassDef = pClassDef;
|
|
pClassDef->AddRef();
|
|
|
|
}
|
|
}
|
|
|
|
// Add the Order qualifier
|
|
|
|
SetPropertyOrderQualifiers(&sel);
|
|
|
|
// Return it.
|
|
// ==========
|
|
|
|
pSink->Add(pClassDef);
|
|
|
|
pClassDef->Release();
|
|
|
|
return pSink->Return(WBEM_NO_ERROR);
|
|
}
|
|
|
|
|