//*************************************************************************** // // (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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 + : 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 + : inner join #SubScopeIds on (ID = a.ObjectScopeId OR (ID = a.ObjectId AND a.ObjectId != %I64d)) // Scope = __Instances=: 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 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 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 r (lpTemp); LPWSTR lpTemp2 = StripQuotes(lpTemp, '%'); CDeleteMe 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; }