windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/repdrvr/wqltosql.cpp

1500 lines
55 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//***************************************************************************
//
// (c) 1999-2001 by Microsoft Corp. All Rights Reserved.
//
// wqltosql.cpp
//
// cvadai 19-Mar-99 Created as prototype for Quasar.
//
//***************************************************************************
#define _WQLTOSQL_CPP_
#pragma warning( disable : 4786 ) // identifier was truncated to 'number' characters in the
#include "precomp.h"
#include <windows.h>
#include <comutil.h>
#include <flexarry.h>
#include <wstring.h>
#include <wqlnode.h>
#include <reposit.h>
#include <time.h>
#include <map>
#include <vector>
#include <wbemcli.h>
#include <wbemint.h>
#include <wqltosql.h>
#include <repcache.h>
#include <reputils.h>
#include <smrtptr.h>
#include <sqlcache.h>
#include <wqllex.h>
#define WMIDB_PROPERTY_THIS 0x1000
//***************************************************************************
//
// TempQL Lex Table
//
//***************************************************************************
/*----------------------------------------------------
References of {objpath} where
ResultClass=XXX
Role=YYY
RequiredQualifier=QualifierName
ClassDefsOnly
Associators of {objpath} where
ResultClass=XXX
AssocClass=YYY
Role=PPP
RequiredQualifier=QualifierName
RequiredAssocQualifier=QualifierName
ClassDefsOnly
------------------------------------------------------*/
#define QUERY_TYPE_CLASSDEFS_ONLY 0x1
#define QUERY_TYPE_GETREFS 0x2
#define QUERY_TYPE_GETASSOCS 0x4
#define QUERY_TYPE_SCHEMA_ONLY 0x8
#define QASSOC_TOK_STRING 101
#define QASSOC_TOK_IDENT 102
#define QASSOC_TOK_DOT 103
#define QASSOC_TOK_EQU 104
#define QASSOC_TOK_COLON 105
#define QASSOC_TOK_ERROR 1
#define QASSOC_TOK_EOF 0
#define ST_IDENT 13
#define ST_STRING 19
#define ST_QSTRING 26
#define ST_QSTRING_ESC 30
//***************************************************************************
//
// CSQLBuilder::FormatSQL
//
//***************************************************************************
HRESULT CSQLBuilder::FormatSQL (SQL_ID dScopeId, SQL_ID dScopeClassId, SQL_ID dSuperScope,
IWbemQuery *pQuery, _bstr_t &sSQL, DWORD dwFlags,
DWORD dwHandleType, SQL_ID *dClassId,
BOOL *bHierarchyQuery, BOOL bTmpTblOK, BOOL *bDeleteQuery,
BOOL *bDefault)
{
// This needs to convert an entire query
// into SQL. We assume that any attempt to get
// a specific object will be done through GetObject.
// This is strictly to return the ObjectIds of heterogenous
// query results.
HRESULT hr = WBEM_S_NO_ERROR;
if (!m_pSchema)
return WBEM_E_NOT_FOUND;
char szTmpNum[25];
BOOL bPartialFailure = FALSE;
m_dwTableCount = 1;
m_bClassSpecified = false;
m_dNamespace = dScopeId;
if (bHierarchyQuery)
*bHierarchyQuery = FALSE;
_bstr_t sColList, sFrom, sWhere;
sColList = L"select a.ObjectId, a.ClassId, a.ObjectScopeId ";
sFrom = L" from ObjectMap as a ";
sWhere = L" where a.ObjectState <> 2";
// Query types:
// ===========
// WMIDB_FLAG_QUERY_SHALLOW + WMIDB_HANDLE_TYPE_SCOPE : ObjectScopeId = %I64d
// WMIDB_FLAG_QUERY_SHALLOW + WMIDB_HANDLE_TYPE_CONTAINER: inner join ContainerObjs as b on b.ContaineeId = a.ObjectId
// and b.ContainerId = %I64d
// WMIDB_FLAG_QUERY_DEEP + <any> : inner join #SubScopeIds on (ID = a.ObjectScopeId OR (ID = a.ObjectId AND a.ObjectId != %I64d))
if (m_dNamespace)
{
sprintf(szTmpNum, "%I64d", m_dNamespace);
// Scope is an __Instances container
// This is shallow by definition.
if (dScopeClassId == INSTANCESCLASSID)
{
sWhere += L" and a.ObjectKey != 'root' and a.ClassId = ";
sWhere += szTmpNum;
char szTmp[25];
sprintf(szTmp, "%I64d", dSuperScope);
sWhere += L" and a.ObjectScopeId in (0, ";
sWhere += szTmp;
sWhere += L")";
}
else
{
// Shallow enumeration
if (!(dwFlags & WMIDB_FLAG_QUERY_DEEP))
{
if (dwHandleType & WMIDB_HANDLE_TYPE_CONTAINER)
{
sFrom += L" inner join ContainerObjs as z on z.ContaineeId = a.ObjectId "
L" and z.ContainerId = ";
sFrom += szTmpNum;
}
else
{
sWhere += L" and a.ObjectKey != 'root' and a.ObjectScopeId in (0,";
sWhere += szTmpNum;
sWhere += L")";
}
}
// Deep enumeration, we enumerate all contained and subscope objects.
else
{
if (bTmpTblOK)
{
sFrom += L" inner join #SubScopeIds on (ID = a.ObjectScopeId OR (ID = a.ObjectId AND a.ObjectId != ";
sFrom += szTmpNum;
sFrom += L"))";
}
else
hr = E_NOTIMPL;
}
}
}
if (dwHandleType & WMIDB_HANDLE_TYPE_CONTAINER)
m_dNamespace = dSuperScope; // Containers are not valid scopes.
sSQL = "";
if (pQuery)
{
SWQLNode *pTop = NULL, *pRoot = NULL;
pQuery->GetAnalysis(WMIQ_ANALYSIS_RESERVED, 0, (void **)&pTop);
if (pTop && pTop->m_pLeft)
{
pRoot = pTop->m_pLeft;
if (bDeleteQuery)
{
if (pRoot->m_dwNodeType == TYPE_SWQLNode_Delete)
*bDeleteQuery = TRUE;
else
*bDeleteQuery = FALSE;
}
// *** WARNING ***
// This is phase I of this formatting code.
// In the future, we will need to also support
// joins, counts, order by, group by, having,
// qualifier queries, and lots of other stuff
// that has yet to be defined.
// For now, this will just return a single
// ObjectId for any query that is passed in.
// Reject any query with Where options (order by, group by)
if (pRoot->m_pRight != NULL)
{
if (pRoot->m_pRight->m_pRight != NULL)
{
bPartialFailure = TRUE;
}
}
// No counts, or multi-table queries.
if (pRoot->m_pLeft != NULL)
{
hr = GetClassFromNode(pRoot->m_pLeft, bDefault);
if (SUCCEEDED(hr))
{
if (m_dClassID == 1)
{
sWhere += L" and a.ClassId = 1";
if (bDefault)
*bDefault = TRUE;
}
else if (m_dClassID == INSTANCESCLASSID)
{
wchar_t wTemp[128];
swprintf(wTemp, L" select a.ObjectId, %I64d, a.ObjectScopeId ", INSTANCESCLASSID);
sColList = wTemp;
sWhere += L" and a.ClassId = 1"; // Classes only
if (bDefault)
*bDefault = TRUE;
}
}
}
if (SUCCEEDED(hr))
{
// Now we parse the where clause.
if (pRoot->m_pRight && pRoot->m_pRight->m_pLeft)
{
_bstr_t sNewSQL;
bool bSys = false;
hr = FormatWhereClause((SWQLNode_RelExpr *)pRoot->m_pRight->m_pLeft, sNewSQL, L"a", bSys);
if (SUCCEEDED(hr))
{
if (bSys)
{
sFrom += L" inner join vSystemProperties as av on av.ObjectId = a.ObjectId ";
}
sWhere += L" AND ";
sWhere += sNewSQL;
// Make sure the results are limited to instances of the requested class
// (Safeguard)
if (!m_bClassSpecified)
{
wchar_t wTemp[256];
if (bSys)
{
swprintf(wTemp, L" and exists (select * from ClassData as j where av.ObjectId = j.ObjectId"
L" and j.ClassId= %I64d) ", m_dClassID);
}
else
{
// __Instances is automatically a shallow hierarchy query
if (m_dClassID != INSTANCESCLASSID)
{
// Until we figure out how to do this in Jet,
// we will only select instances of the requested class.
if (bTmpTblOK)
wcscpy(wTemp, L" AND EXISTS (select b.ClassId from #Children as b "
L" where b.ClassId = a.ClassId )");
else
swprintf(wTemp, L" AND a.ClassId = %I64d", m_dClassID);
if (bHierarchyQuery)
*bHierarchyQuery = TRUE;
}
}
sWhere += wTemp;
}
}
}
else
{
// __Instances is automatically a shallow hierarchy query
if (m_dClassID != INSTANCESCLASSID)
{
wchar_t wTemp[256];
// If no criteria, make sure we only get the class we asked for.
if (bTmpTblOK)
wcscpy(wTemp, L" AND EXISTS (select b.ClassId from #Children as b "
L" where b.ClassId = a.ClassId)");
else
swprintf(wTemp, L" AND a.ClassId = %I64d", m_dClassID);
if (bHierarchyQuery)
*bHierarchyQuery = TRUE;
sWhere += wTemp;
}
}
sSQL = sColList + sFrom + sWhere;
if (dClassId)
*dClassId = m_dClassID;
}
}
}
else
hr = WBEM_E_INVALID_PARAMETER;
if ((SUCCEEDED(hr) && bPartialFailure))
hr = WBEM_E_PROVIDER_NOT_CAPABLE;
return hr;
}
//***************************************************************************
//
// CSQLBuilder::FormatSQL
//
//***************************************************************************
HRESULT CSQLBuilder::FormatSQL (SQL_ID dScopeId, SQL_ID dScopeClassId, SQL_ID dSuperScope,
SQL_ID dTargetObjID, LPWSTR pResultClass,
LPWSTR pAssocClass, LPWSTR pRole, LPWSTR pResultRole, LPWSTR pRequiredQualifier,
LPWSTR pRequiredAssocQualifier, DWORD dwQueryType, _bstr_t &sSQL, DWORD dwFlags,
DWORD dwHandleType, SQL_ID *_dAssocClass, SQL_ID *_dResultClass, BOOL bIsClass)
{
// Query types:
// ===========
// WMIDB_FLAG_QUERY_SHALLOW + WMIDB_HANDLE_TYPE_SCOPE : ObjectScopeId = %I64d
// WMIDB_FLAG_QUERY_SHALLOW + WMIDB_HANDLE_TYPE_CONTAINER: inner join ContainerObjs as b on b.ContaineeId = a.ObjectId
// and b.ContainerId = %I64d
// WMIDB_FLAG_QUERY_DEEP + <any> : inner join #SubScopeIds on (ID = a.ObjectScopeId OR (ID = a.ObjectId AND a.ObjectId != %I64d))
// Scope = __Instances=<Class>: and ClassId = %I64d
HRESULT hr = WBEM_S_NO_ERROR;
DWORD dwRoleID = 0, dwResultRole = 0, dwAssocQfr = 0;
SQL_ID dAssocClass = 0, dTargetObj = 0, dThisClassId = 0;
bool bWhereReq = true;
_bstr_t sRole = "", sAssocQfr = "", sAssocClass = "", sResultRole = "";
_bstr_t sName;
SQL_ID dwSuperClassID;
SQL_ID dwScopeID;
DWORD dwTemp;
_bstr_t sJoin = L"RefId";
hr = m_pSchema->GetClassInfo(dTargetObjID, sName, dwSuperClassID, dwScopeID, dwTemp);
if (SUCCEEDED(hr))
{
dThisClassId = dTargetObjID;
sJoin = L"RefClassId";
}
hr = WBEM_S_NO_ERROR;
m_dNamespace = dScopeId;
if (dwQueryType & QUERY_TYPE_CLASSDEFS_ONLY)
sSQL = L"select distinct a.ClassId, 1, 0 ";
else
sSQL = L"select a.ObjectId, a.ClassId, a.ObjectScopeId ";
sSQL += L" from ObjectMap as a ";
if (m_dNamespace)
{
char szTmp[25];
sprintf(szTmp, "%I64d", m_dNamespace);
if (dScopeClassId == INSTANCESCLASSID)
{
sSQL += L" WHERE a.ClassId = ";
sSQL += szTmp;
sprintf(szTmp, "%I64d", dSuperScope);
sSQL += L" and a.ObjectScopeId = ";
sSQL += szTmp;
}
else
{
if (!(dwFlags & WMIDB_FLAG_QUERY_DEEP))
{
if (dwHandleType & WMIDB_HANDLE_TYPE_CONTAINER)
{
sSQL += L" inner join ContainerObjs as z on z.ContaineeId = a.ObjectId "
L" WHERE z.ContainerId = ";
sSQL += szTmp;
}
else
{
sSQL += " WHERE a.ObjectScopeId = ";
sSQL += szTmp;
}
}
else
{
sSQL += L" inner join #SubScopeIds on (ID = a.ObjectScopeId OR (ID = a.ObjectId AND a.ObjectId != ";
sSQL += szTmp;
sSQL += L" )) ";
}
}
sSQL += L" AND ";
}
else
sSQL += " WHERE ";
sSQL += " a.ObjectState <> 2 AND ";
// Containers are not valid scopes.
if (dwHandleType & WMIDB_HANDLE_TYPE_CONTAINER)
m_dNamespace = dSuperScope;
// RESULTCLASS
if (pResultClass != NULL)
{
wchar_t wTemp[100];
// Get the class ID of this class
hr = m_pSchema->GetClassID(pResultClass, m_dNamespace, dThisClassId);
if (FAILED(hr))
goto Exit;
swprintf(wTemp, L" a.ClassId = %I64d", dThisClassId);
bWhereReq = false;
sSQL += wTemp;
if (_dResultClass)
*_dResultClass = dThisClassId;
}
// REQUIREDQUALIFIER
if (pRequiredQualifier != NULL)
{
/*
wchar_t wTemp[255];
DWORD dwPropId = 0;
hr = m_pSchema->GetPropertyID(pRequiredQualifier, dThisClassId, REPDRVR_FLAG_QUALIFIER,
REPDRVR_IGNORE_CIMTYPE, dwPropId, NULL, NULL, NULL, TRUE);
if (FAILED(hr))
goto Exit;
if (!bWhereReq)
sSQL += L" AND ";
// FIXME: This will only work on class-level qualifiers.
// It will not work on instance qualifiers.
swprintf(wTemp, L"EXISTS (select ClassId from ClassData as c where a.ClassId = c.ObjectId and c.PropertyId = %ld)",
dwPropId);
bWhereReq = false;
sSQL += wTemp;
*/
}
if (!bWhereReq)
sSQL += " AND ";
// ROLE
if (pRole)
{
wchar_t wTemp[512];
swprintf(wTemp, L" and b.PropertyId in (select PropertyId from PropertyMap where PropertyName = '%s')", pRole);
sRole = wTemp;
}
// RESULTROLE
if (pResultRole)
{
wchar_t wTemp[512];
swprintf(wTemp, L" and b.PropertyId in (select PropertyId from PropertyMap where PropertyName = '%s')", pResultRole);
sResultRole = wTemp;
}
// REQUIREDASSOCQUALIFIER
if (pRequiredAssocQualifier)
{
/*
wchar_t wTemp[256];
hr = m_pSchema->GetPropertyID(pRequiredAssocQualifier, dThisClassId, REPDRVR_FLAG_QUALIFIER,
REPDRVR_IGNORE_CIMTYPE, dwAssocQfr, NULL, NULL, NULL, TRUE);
if (FAILED(hr))
goto Exit;
swprintf(wTemp, L" AND EXISTS (select ObjectId from ClassData as d where b.ClassId = d.ObjectId and d.PropertyId = %ld)",
dwAssocQfr);
sAssocQfr = wTemp;
*/
}
// ASSOCCLASS
if (pAssocClass)
{
wchar_t wTemp[256];
hr = m_pSchema->GetClassID(pAssocClass, m_dNamespace, dAssocClass);
if (FAILED(hr))
goto Exit;
swprintf(wTemp, L" AND b.ClassId = %I64d", dAssocClass);
sAssocClass = wTemp;
if (_dAssocClass)
*_dAssocClass = dAssocClass;
}
if (dwQueryType & QUERY_TYPE_GETREFS)
{
wchar_t wTemp[1024];
if (!bIsClass)
{
swprintf(wTemp, L" EXISTS (select ObjectId from ClassData as b where a.ObjectId = b.ObjectId "
L" %s and b.%s = %I64d)", (const wchar_t *)sRole, (const wchar_t *)sJoin, dTargetObjID);
}
else
{
swprintf(wTemp, L" a.ClassId = 1 AND EXISTS (select r.ClassId from ReferenceProperties as r "
L" where r.ClassId = a.ObjectId and r.RefClassId = %I64d)", dTargetObjID);
}
sSQL += wTemp;
}
else
{
wchar_t wTemp[2048];
if (!bIsClass)
{
swprintf(wTemp, L" EXISTS (select b.RefId from ClassData as b inner join ClassData as c on c.ObjectId = b.ObjectId "
L" where c.RefId = a.ObjectId and b.%s = %I64d and c.RefId <> b.RefId %s%s%s%s)", (const wchar_t *)sJoin,
dTargetObjID, (const wchar_t *)sRole, (const wchar_t *)sResultRole, (const wchar_t *)sAssocClass,
(const wchar_t *)sAssocQfr);
}
else
{
swprintf(wTemp, L" a.ClassId = 1 AND EXISTS (select r.ClassId from ReferenceProperties as r "
L" INNER JOIN ReferenceProperties as r2 on r.ClassId = r2.ClassId and r.PropertyId <> r2.PropertyId"
L" where r.ClassId = a.ObjectId and r2.RefClassId = %I64d)", dTargetObjID);
}
sSQL += wTemp;
}
Exit:
return hr;
}
//***************************************************************************
//
// CSQLBuilder::FormatWhereClause
//
//***************************************************************************
HRESULT CSQLBuilder::FormatWhereClause (SWQLNode_RelExpr *pNode, _bstr_t &sSQL, LPCWSTR lpJoinAlias, bool &bSysPropsUsed)
{
HRESULT hr = WBEM_S_NO_ERROR;
BOOL bDone = FALSE;
SQL_ID dClassId = 0;
// For each node, we need to
// 1. Look at the node type (and, or, not or typed)
// 2. If not typed, group and continue
// 3. If typed, construct the clause based on the property ID of the
// property, the value and the operator.
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, lpJoinAlias, bSysPropsUsed);
}
if (dwType == WQL_TOK_OR)
sTemp += " OR ";
else
sTemp += " AND ";
if (pNode->m_pRight)
{
hr |= FormatWhereClause((SWQLNode_RelExpr *)pNode->m_pRight, sTemp, lpJoinAlias, bSysPropsUsed);
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, lpJoinAlias, bSysPropsUsed);
sSQL += sTemp;
}
m_bClassSpecified = false; // whatever we've done probably negated the class qualifier.
break;
default: // Typed expression
m_dwTableCount++;
SWQLTypedExpr *pExpr = ((SWQLNode_RelExpr *)pNode)->m_pTypedExpr;
if (pExpr != NULL)
{
DWORD dwProp1 = 0, dwProp2 = 0, dwOp = 0;
DWORD dwStorage1 = 0, dwStorage2 = 0;
DWORD dwKey1, dwKey2;
_bstr_t sPropName, sValue, sSrc;
wchar_t sAlias[256];
swprintf(sAlias, L"%s%ld", lpJoinAlias, m_dwTableCount);
_bstr_t sColName;
if (pExpr->m_pColRef)
sColName = pExpr->m_pColRef;
else if (pExpr->m_pIntrinsicFuncOnColRef &&
!_wcsicmp(pExpr->m_pIntrinsicFuncOnColRef, L"datepart") &&
pExpr->m_pLeftFunction)
{
sColName = ((SWQLNode_Datepart *)pExpr->m_pLeftFunction)->m_pColRef->m_pColName;
}
hr = GetPropertyID(m_dClassID, pExpr->m_pQNLeft, sColName, dwProp1, dwStorage1, dwKey1);
if (SUCCEEDED(hr))
{
if (dwStorage1 == WMIDB_PROPERTY_THIS)
{
// Special-case: the __this property.
hr = m_pSchema->GetClassID(pExpr->m_pConstValue->m_Value.m_pString, m_dNamespace, dClassId);
if (SUCCEEDED(hr) && dClassId != 1)
{
sSQL += L" a.ObjectId in (";
SQL_ID *pIDs = NULL;
int iNumChildren = 0;
hr = m_pSchema->GetDerivedClassList(dClassId, &pIDs, iNumChildren);
if (SUCCEEDED(hr))
{
char szTmp[25];
sprintf(szTmp, "%I64d", dClassId);
sSQL += szTmp;
for (int i = 0; i < iNumChildren; i++)
{
sSQL += L",";
sprintf(szTmp, "%I64d", pIDs[i]);
sSQL += szTmp;
}
delete pIDs;
sSQL += L")";
}
}
}
else
{
GetStorageTable(dwStorage1, dwKey1, sSrc);
if (dwStorage1 == WMIDB_STORAGE_COMPACT)
swprintf(sAlias, L"%sv", lpJoinAlias);
// Can't query anything stored as image
if (dwStorage1 == WMIDB_STORAGE_IMAGE || dwStorage2 == WMIDB_STORAGE_IMAGE)
return WBEM_E_QUERY_NOT_IMPLEMENTED;
dwOp = pExpr->m_dwRelOperator;
hr = FunctionalizeProperty (sAlias, dwStorage1, pExpr->m_pIntrinsicFuncOnColRef, pExpr->m_pLeftFunction, pExpr->m_pColRef, sPropName);
if (SUCCEEDED(hr))
{
if (pExpr->m_pConstValue != NULL)
{
CIMTYPE ct=0;
m_pSchema->GetPropertyInfo(dwProp1, NULL, NULL, NULL, (DWORD *)&ct);
if (ct != CIM_DATETIME)
hr = FunctionalizeValue (pExpr->m_pConstValue, dwStorage1, pExpr->m_pIntrinsicFuncOnConstValue, sValue);
else
{
// Skip this token...
// The core will post-filter.
bDone = TRUE;
sSQL += L" 1=1 ";
}
}
else if (pExpr->m_pJoinColRef != NULL)
{
// SPECIAL CASE. To compare two properties, we deliberately cause a join to happen.
m_dwTableCount++;
wchar_t sAlias2[256];
_bstr_t sSrc2;
_bstr_t sPropName2, sExtra = L"";
if (pExpr->m_pJoinColRef)
sColName = pExpr->m_pJoinColRef;
else if (pExpr->m_pIntrinsicFuncOnJoinColRef &&
!_wcsicmp(pExpr->m_pIntrinsicFuncOnJoinColRef, L"datepart") &&
pExpr->m_pRightFunction)
{
sColName = ((SWQLNode_Datepart *)pExpr->m_pRightFunction)->m_pColRef->m_pColName;
}
hr = GetPropertyID(m_dClassID, pExpr->m_pQNRight, sColName, dwProp2, dwStorage2, dwKey2);
GetStorageTable(dwStorage2, dwKey2, sSrc2);
if (dwStorage2 == WMIDB_STORAGE_COMPACT)
swprintf(sAlias2, L"%sv", lpJoinAlias);
else
swprintf(sAlias2, L"%s%ld", lpJoinAlias, m_dwTableCount);
hr = FunctionalizeProperty (sAlias2, dwStorage2, pExpr->m_pIntrinsicFuncOnJoinColRef, pExpr->m_pRightFunction, pExpr->m_pJoinColRef, sPropName2);
if (pExpr->m_pQNRight)
{
SWQLQualifiedNameField *pNF = (SWQLQualifiedNameField *)pExpr->m_pQNRight->m_aFields[0];
hr = FormatPositionQuery(pNF, pExpr->m_dwRightArrayIndex, sAlias2, sTemp);
if (SUCCEEDED(hr))
sExtra = sTemp;
}
if (pExpr->m_pQNLeft)
{
SWQLQualifiedNameField *pNF = (SWQLQualifiedNameField *)pExpr->m_pQNLeft->m_aFields[0];
hr = FormatPositionQuery(pNF, pExpr->m_dwLeftArrayIndex, sAlias, sTemp);
if (SUCCEEDED(hr))
sExtra += sTemp;
}
if (SUCCEEDED(hr))
{
wchar_t wTempSQL[2048];
// If the right side is a system property, we just treat this
// like a regular comparison.
if (dwStorage2 == WMIDB_STORAGE_COMPACT)
{
bSysPropsUsed = true;
bDone = false;
sValue = sPropName2;
}
// If the left side is a system property, we need to reverse the
// values and let it through...
else if (dwStorage1 == WMIDB_STORAGE_COMPACT)
{
sValue = sPropName;
sPropName = sPropName2;
wcscpy(sAlias,sAlias2);
dwProp1 = dwProp2;
bSysPropsUsed = true;
dwStorage1 = dwStorage2;
sSrc = sSrc2;
}
// Otherwise, we create a new join and wrap up.
else
{
LPWSTR lpOp = GetOperator(dwOp);
CDeleteMe <wchar_t> r (lpOp);
swprintf(wTempSQL, L" EXISTS "
L" (select %s.ObjectId from %s as %s inner join %s as %s on %s%s%s and %s.ObjectId = %s.ObjectId "
L" where %s.ObjectId=%s.ObjectId and %s.PropertyId = %ld and %s.PropertyId = %ld%s)",
sAlias, (const wchar_t *)sSrc, sAlias,
(const wchar_t *)sSrc2, sAlias2, (const wchar_t *)sPropName,
lpOp,(const wchar_t *)sPropName2, sAlias,
sAlias2, lpJoinAlias, sAlias, sAlias,
dwProp1, sAlias2, dwProp2, (const wchar_t *)sExtra);
bDone = TRUE;
sSQL += wTempSQL;
}
}
}
if (SUCCEEDED(hr) && !bDone)
{
_bstr_t sPrefix = "";
LPWSTR lpOp = GetOperator(dwOp);
if (!lpOp || !wcslen(lpOp))
{
switch (dwOp)
{
case WQL_TOK_NULL:
case WQL_TOK_ISNULL:
sPrefix = " NOT ";
sValue = "";
break;
case WQL_TOK_NOT_NULL:
sValue = "";
break;
case WQL_TOK_ISA:
sPropName = sAlias;
sPropName += L".RefClassId";
delete lpOp;
lpOp = new wchar_t [10];
if (lpOp)
{
hr = m_pSchema->GetClassID(pExpr->m_pConstValue->m_Value.m_pString, m_dNamespace, dClassId);
if (SUCCEEDED(hr) && dClassId != 1)
{
wcscpy(lpOp, L" in ");
sValue = L"(";
SQL_ID *pIDs = NULL;
int iNumChildren = 0;
hr = m_pSchema->GetDerivedClassList(dClassId, &pIDs, iNumChildren);
if (SUCCEEDED(hr))
{
char szTmp[25];
sprintf(szTmp, "%I64d", dClassId);
sValue += szTmp;
for (int i = 0; i < iNumChildren; i++)
{
sValue += L",";
sprintf(szTmp, "%I64d", pIDs[i]);
sValue += szTmp;
}
delete pIDs;
sValue += L")";
}
if (dwStorage1 == WMIDB_STORAGE_COMPACT)
dwStorage1 = WMIDB_STORAGE_REFERENCE;
}
else
{
wcscpy(lpOp, L" <> ");
sValue = L"0";
}
}
else
hr = WBEM_E_OUT_OF_MEMORY;
break;
case WQL_TOK_BETWEEN:
delete lpOp;
lpOp = new wchar_t [10];
if (lpOp)
{
wcscpy(lpOp, L" between ");
sValue += " and ";
hr = FunctionalizeValue (pExpr->m_pConstValue2, dwStorage2, pExpr->m_pIntrinsicFuncOnConstValue, sTemp);
sValue += sTemp;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
break;
case WQL_TOK_NOT_IN:
case WQL_TOK_IN:
case WQL_TOK_IN_SUBSELECT:
case WQL_TOK_NOT_IN_SUBSELECT:
case WQL_TOK_IN_CONST_LIST:
case WQL_TOK_NOT_IN_CONST_LIST:
delete lpOp;
lpOp = new wchar_t [10];
if (lpOp)
{
wcscpy(lpOp, L"");
if (pExpr->m_dwRelOperator == WQL_TOK_NOT_IN ||
pExpr->m_dwRelOperator == WQL_TOK_NOT_IN_SUBSELECT ||
pExpr->m_dwRelOperator == WQL_TOK_NOT_IN_CONST_LIST)
{
wcscpy(lpOp, L" not ");
}
wcscat(lpOp, L" in ");
sValue = "(";
if (pExpr->m_dwRelOperator == WQL_TOK_IN_SUBSELECT ||
pExpr->m_dwRelOperator == WQL_TOK_NOT_IN_SUBSELECT)
{
// If a subselect, we need to construct an entirely new tree, passing
// in the current alias.
_bstr_t sTemp;
m_dwTableCount++;
wchar_t wAlias3[256];
swprintf(wAlias3, L"%s%ld", lpJoinAlias, m_dwTableCount);
wchar_t *pColName = sPropName;
pColName += wcslen(sAlias)+1;
hr = FormatSimpleSelect (wAlias3, pColName, pExpr->m_pSubSelect, sTemp);
if (SUCCEEDED(hr))
sValue += sTemp;
}
else
{
// If a const list, behaves as normal
if (pExpr->m_pConstList)
{
for (int iPos = 0; iPos < pExpr->m_pConstList->m_aValues.Size(); iPos++)
{
if (iPos > 0)
sValue += ",";
hr = FunctionalizeValue(((SWQLTypedConst *)pExpr->m_pConstList->m_aValues.GetAt(iPos)), dwStorage1, pExpr->m_pIntrinsicFuncOnConstValue, sTemp);
sValue += sTemp;
}
}
}
sValue += ")";
}
else
hr = WBEM_E_OUT_OF_MEMORY;
break;
default:
break;
}
}
if (SUCCEEDED(hr))
{
long lLen = wcslen(sValue) + 512;
wchar_t *pTempSQL = new wchar_t[lLen];
CDeleteMe <wchar_t> r (pTempSQL);
if (pTempSQL)
{
if (sValue.length() != 0)
{
if (dwStorage1 != WMIDB_STORAGE_COMPACT)
sTemp = L" and ";
sTemp += sPropName + lpOp + sValue;
sValue = sTemp;
}
// Set array position (for left value only)
if (pExpr->m_dwLeftFlags & WQL_FLAG_COMPLEX_NAME)
{
if (pExpr->m_pQNLeft)
{
SWQLQualifiedNameField *pNF = (SWQLQualifiedNameField *)pExpr->m_pQNLeft->m_aFields[0];
hr = FormatPositionQuery(pNF, pExpr->m_dwLeftArrayIndex, sAlias, sTemp);
if (SUCCEEDED(hr))
sValue + sTemp;
}
}
if (dwStorage1 != WMIDB_STORAGE_COMPACT)
{
swprintf(pTempSQL, L"%s EXISTS (select %s.ObjectId from %s as %s where %s.ObjectId=%s.ObjectId and %s.PropertyId = %ld %s)",
(const wchar_t *)sPrefix, sAlias, (const wchar_t *)sSrc, sAlias,
sAlias, lpJoinAlias, sAlias,
dwProp1, (const wchar_t *)sValue);
}
else
{
bSysPropsUsed = true;
// This is a straight comparison on a system property...
swprintf(pTempSQL, L" %s",
(const wchar_t *)sValue);
}
sSQL += pTempSQL;
}
else
hr = WBEM_E_OUT_OF_MEMORY;
delete lpOp;
}
}
}
}
}
}
break;
}
}
return hr;
}
//***************************************************************************
//
// CSQLBuilder::GetStorageTable
//
//***************************************************************************
HRESULT CSQLBuilder::GetStorageTable(DWORD dwStorage, DWORD dwKey, _bstr_t &sTable)
{
if (dwStorage == WMIDB_STORAGE_COMPACT)
sTable = L"vSystemProperties";
else
{
sTable = L"ClassData";
if (dwKey & 4 || dwKey & 8)
{
switch(dwStorage)
{
case WMIDB_STORAGE_STRING:
sTable = L"IndexStringData";
break;
case WMIDB_STORAGE_NUMERIC:
sTable = L"IndexNumericData";
break;
case WMIDB_STORAGE_REAL:
sTable = L"IndexRealData";
break;
case WMIDB_STORAGE_REFERENCE:
sTable = L"IndexRefData";
break;
}
}
}
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// CSQLBuilder::GetPropertyID
//
//***************************************************************************
HRESULT CSQLBuilder::GetPropertyID (SQL_ID dClassID, SWQLQualifiedName *pQN, LPCWSTR pColRef, DWORD &PropID, DWORD &Storage, DWORD &Flags)
{
// If this is an embedded object property,
// we need the actual class ID. The only way
// to do that is the walk through all the properties,
// and reconcile each layer.
BOOL bThis = FALSE;
HRESULT hr = WBEM_S_NO_ERROR;
SQL_ID dRefClassId = dClassID;
if (pQN != NULL)
{
/*
for (int i = pQN->GetNumNames() - 1; i >= 0; i--)
{
SWQLQualifiedNameField *pNF = (SWQLQualifiedNameField *)pQN->m_aFields[i];
if (pNF)
{
hr = m_pSchema->GetPropertyID(pNF->m_pName, dRefClassId, 0,
REPDRVR_IGNORE_CIMTYPE, PropID, &dClassID, NULL, NULL, TRUE);
if (SUCCEEDED(hr))
{
// Look up the property ID for this class.
hr = m_pSchema->GetPropertyInfo(PropID, NULL, NULL, &Storage,
NULL, &Flags);
}
}
}
*/
hr = WBEM_E_PROVIDER_NOT_CAPABLE;
}
else if (pColRef != NULL)
{
wchar_t wName[1024];
if (!_wcsicmp(pColRef, L"__this"))
{
Storage = WMIDB_PROPERTY_THIS;
bThis = TRUE;
m_bClassSpecified = true; // they are specifying which classes they want...
}
else
{
wcscpy(wName, pColRef);
// Look up the property ID for this class.
hr = m_pSchema->GetPropertyID(wName, m_dClassID, 0, REPDRVR_IGNORE_CIMTYPE,
PropID, &dClassID, NULL, NULL, TRUE);
if (SUCCEEDED(hr))
hr = m_pSchema->GetPropertyInfo(PropID, NULL, NULL, &Storage,
NULL, &Flags);
}
}
else
hr = WBEM_E_INVALID_PARAMETER;
if (!bThis)
{
if (m_dClassID == dClassID)
m_bClassSpecified = true;
if (Flags & REPDRVR_FLAG_SYSTEM)
Storage = WMIDB_STORAGE_COMPACT;
}
return hr;
}
//***************************************************************************
//
// CSQLBuilder::FunctionalizeProperty
//
//***************************************************************************
HRESULT CSQLBuilder::FunctionalizeProperty (LPCWSTR lpAlias, DWORD dwType, LPWSTR lpFuncName, SWQLNode *pFunction, LPWSTR lpColName, _bstr_t &sProp)
{
// Apply any functions to the appropriate column of ClassData
HRESULT hr = WBEM_S_NO_ERROR;
bool bRef = false;
_bstr_t sTemp;
if (lpFuncName != NULL)
{
if (!_wcsicmp(lpFuncName, L"datepart"))
sTemp = L"substring";
else
sTemp = lpFuncName;
sTemp += "(";
}
sTemp += lpAlias;
sTemp += L".";
switch(dwType)
{
case WMIDB_STORAGE_STRING:
// Unicode
sTemp += L"PropertyStringValue";
break;
case WMIDB_STORAGE_NUMERIC:
// SQL_ID
sTemp += L"PropertyNumericValue";
break;
case WMIDB_STORAGE_REAL:
// real
sTemp += L"PropertyRealValue";
break;
case WMIDB_STORAGE_REFERENCE:
// REF: Since this is stored as a number, we have to
// subselect to get the real path, and apply all
// functions to it.
bRef = true;
sTemp = L"(select ObjectPath from ObjectMap where ObjectId = ";
sTemp += lpAlias;
sTemp += ".RefId)";
break;
case WMIDB_STORAGE_COMPACT:
// System property, using vSystemProperties
sTemp += lpColName;
break;
default:
hr = WBEM_E_INVALID_QUERY;
break;
}
if (pFunction)
{
if (pFunction->m_dwNodeType == TYPE_SWQLNode_Datepart)
{
sTemp += ",";
switch(((SWQLNode_Datepart *)pFunction)->m_nDatepart)
{
case WQL_TOK_YEAR:
sTemp += L"1,4";
break;
case WQL_TOK_MONTH:
sTemp += L"5,2";
break;
case WQL_TOK_DAY:
sTemp += L"7,2";
break;
case WQL_TOK_HOUR:
sTemp += L"9,2";
break;
case WQL_TOK_MINUTE:
sTemp += L"11,2";
break;
case WQL_TOK_SECOND:
sTemp += L"13,2";
break;
case WQL_TOK_MILLISECOND:
sTemp += L"16,6";
break;
default:
hr = WBEM_E_INVALID_QUERY;
break;
}
}
}
if (lpFuncName != NULL)
{
sTemp += ")";
}
if (SUCCEEDED(hr))
sProp = sTemp;
return hr;
}
//***************************************************************************
//
// CSQLBuilder::FunctionalizeValue
//
//***************************************************************************
HRESULT CSQLBuilder::FunctionalizeValue(SWQLTypedConst *pValue, DWORD dwType, LPWSTR lpFuncName, _bstr_t &sValue)
{
// Apply any functions to the data, and add quotes as appropriate.
HRESULT hr = WBEM_S_NO_ERROR;
_bstr_t sTemp;
if (lpFuncName)
{
sTemp = lpFuncName;
sTemp += L"(";
}
if (pValue->m_dwType == VT_LPWSTR) {
sTemp += L"'";
LPWSTR lpTemp = StripQuotes(pValue->m_Value.m_pString);
CDeleteMe <wchar_t> r (lpTemp);
LPWSTR lpTemp2 = StripQuotes(lpTemp, '%');
CDeleteMe <wchar_t> r2 (lpTemp2);
if (dwType == WMIDB_STORAGE_COMPACT && !wcslen(lpTemp2))
sTemp += L"meta_class";
else
sTemp += lpTemp2;
sTemp += L"'";
}
else if(pValue->m_dwType == VT_NULL)
{
hr = WBEM_E_INVALID_QUERY;
}
else if (pValue->m_dwType == VT_I4)
{
char szTmp[25];
sprintf(szTmp, "%ld", pValue->m_Value.m_lValue);
sTemp += szTmp;
}
else if (pValue->m_dwType == VT_BOOL)
{
if (pValue->m_Value.m_bValue)
sTemp += L"1";
else
sTemp += L"0";
}
else if (pValue->m_dwType == VT_R8)
{
char szTmp[25];
sprintf(szTmp, "%lG", pValue->m_Value.m_dblValue);
sTemp += szTmp;
}
if (lpFuncName)
{
sTemp += L")";
}
if (SUCCEEDED(hr))
sValue = sTemp;
return hr;
}
//***************************************************************************
//
// CSQLBuilder::FormatSimpleSelect
//
//***************************************************************************
HRESULT CSQLBuilder::FormatSimpleSelect (LPCWSTR lpUseAlias,LPCWSTR lpColName, SWQLNode *pTop, _bstr_t &sSQL)
{
// Internal use only: This is to format subselects, so it should
// consist of a single column select from a known class.
HRESULT hr = WBEM_S_NO_ERROR;
SQL_ID dClassID;
DWORD dwPropID = 0, dwStorage = 0, dwFlags = 0;
_bstr_t sSrc = L"";
_bstr_t sExtra=L"";
_bstr_t sSubCol = lpColName;
if (pTop)
{
if (pTop->m_pLeft)
{
if (pTop->m_pLeft->m_pRight)
{
SWQLNode_TableRef *pRef = (SWQLNode_TableRef *)pTop->m_pLeft->m_pRight->m_pLeft;
hr = m_pSchema->GetClassID(pRef->m_pTableName, m_dNamespace, dClassID);
if (FAILED(hr))
hr = WBEM_E_INVALID_QUERY;
}
else
hr = WBEM_E_INVALID_QUERY;
if (pTop->m_pLeft->m_pLeft)
{
SWQLNode_ColumnList *pList = (SWQLNode_ColumnList *)pTop->m_pLeft->m_pLeft;
SWQLColRef *pCol = (SWQLColRef *)pList->m_aColumnRefs[0];
if (pCol)
{
_bstr_t sName = pCol->m_pColName;
if (pCol->m_dwFlags & WQL_FLAG_COMPLEX_NAME)
{
SWQLQualifiedName *pQN = pCol->m_pQName;
if (pQN)
{
hr = FormatPositionQuery((SWQLQualifiedNameField *)pQN->m_aFields[0], pCol->m_dwArrayIndex, lpUseAlias, sExtra);
}
}
hr = GetPropertyID(dClassID, pCol->m_pQName, pCol->m_pColName, dwPropID, dwStorage, dwFlags);
if (SUCCEEDED(hr))
{
GetStorageTable(dwStorage, dwFlags, sSrc);
// If we are comparing different types,
// or using a system property, get the new col name
FunctionalizeProperty (lpUseAlias, dwStorage, NULL, NULL, pCol->m_pColName, sSubCol);
}
}
}
}
else
hr = WBEM_E_INVALID_QUERY;
}
else
hr = WBEM_E_INVALID_QUERY;
if (SUCCEEDED(hr))
{
wchar_t wTemp[256];
wchar_t wWhere[512];
_bstr_t sTemp, sTempSQL;
// Construct the *simple* where clause....
// If there is any where element at all, we need to ditch the
// simple approach and revert to the subselect set...
// ==========================================================
swprintf(wTemp, L"select %s from %s as %s",
(const wchar_t *)sSubCol,
(const wchar_t *)sSrc, lpUseAlias);
sTemp = wTemp;
if (dwStorage == WMIDB_STORAGE_COMPACT)
swprintf(wWhere, L" where %s.ClassId = %I64d", lpUseAlias, dClassID);
else
swprintf(wWhere, L" where PropertyId = %ld%s", dwPropID, (const wchar_t *)sExtra);
if (pTop->m_pRight)
{
bool bSysPropsUsed = false;
hr = FormatWhereClause((SWQLNode_RelExpr *)pTop->m_pRight->m_pLeft, sTempSQL, lpUseAlias, bSysPropsUsed);
if (SUCCEEDED(hr) && sTempSQL.length() > 0)
{
if (bSysPropsUsed && !(dwStorage == WMIDB_STORAGE_COMPACT))
{
wchar_t NewSQL[1024];
swprintf(NewSQL, L" inner join vSystemProperties as %sv on %sv.ObjectId = %s.ObjectId and %sv.ClassId = %I64d",
lpUseAlias, lpUseAlias, lpUseAlias, lpUseAlias, dClassID);
sTemp += NewSQL;
}
sTemp += wWhere;
sTemp += L" AND ";
sTemp += sTempSQL;
}
else
sTemp += wWhere;
}
sSQL = sTemp;
}
return hr;
}
//***************************************************************************
//
// CSQLBuilder::FormatPositionQuery
//
//***************************************************************************
HRESULT CSQLBuilder::FormatPositionQuery (SWQLQualifiedNameField *pQNF, int iPos, LPCWSTR lpAlias, _bstr_t &sQuery)
{
HRESULT hr = WBEM_S_NO_ERROR;
wchar_t wTemp[128];
int iTemp;
if (pQNF)
{
if (pQNF->m_bArrayRef)
{
iTemp = (int)pQNF->m_dwArrayIndex;
}
}
else
iTemp = iPos;
swprintf(wTemp, L"and %s.ArrayPos = %ld", lpAlias, iTemp);
sQuery = wTemp;
return hr;
}
//***************************************************************************
//
// CSQLBuilder::GetClassFromNode
//
//***************************************************************************
HRESULT CSQLBuilder::GetClassFromNode (SWQLNode *pNode, BOOL *bDefaultStorage)
{
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;
}
// Query = "select * from __Instances" : fudge it so they get all classes in this namespace.
hr = m_pSchema->GetClassID(lpTableName, m_dNamespace, m_dClassID);
if (FAILED(hr))
hr = WBEM_E_INVALID_QUERY;
// System classes are always default.
if (bDefaultStorage)
{
if (lpTableName[0] == L'_')
*bDefaultStorage = TRUE;
else
*bDefaultStorage = FALSE;
}
return hr;
}