|
|
//***************************************************************************
//
// Copyright � Microsoft Corporation. All rights reserved.
//
// analyser.cpp
//
// Purpose: Performs query analysis
//
//***************************************************************************
#include "precomp.h"
#pragma warning( disable : 4290 )
#include <CHString.h>
#include "analyser.h"
#include <stack>
#include <vector>
#include <comdef.h>
#include <scopeguard.h>
#include <autoptr.h>
void AutoDestructStack(std::stack<SQL_LEVEL_1_RPN_EXPRESSION*>& X ) { while(!X.empty()) { delete X.top(); X.pop(); } }
HRESULT CQueryAnalyser::GetNecessaryQueryForProperty (
IN SQL_LEVEL_1_RPN_EXPRESSION *pExpr, IN LPCWSTR wszPropName, DELETE_ME SQL_LEVEL_1_RPN_EXPRESSION *&pNewExpr ) { pNewExpr = NULL ;
// Class name and selected properties are ignored; we look at tokens only
// ======================================================================
std::stack<SQL_LEVEL_1_RPN_EXPRESSION*> ExprStack; ScopeGuard clearStack = MakeGuard(AutoDestructStack, ByRef(ExprStack)); HRESULT hres = WBEM_S_NO_ERROR;
// "Evaluate" the query
// ====================
if(pExpr->nNumTokens == 0) { // Empty query --- no information
// ==============================
pNewExpr = new SQL_LEVEL_1_RPN_EXPRESSION; if ( ! pNewExpr ) { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
return WBEM_S_NO_ERROR; }
for(int i = 0; i < pExpr->nNumTokens; i++) { SQL_LEVEL_1_TOKEN &Token = pExpr->pArrayOfTokens[i]; wmilib::auto_ptr<SQL_LEVEL_1_RPN_EXPRESSION> pNew(new SQL_LEVEL_1_RPN_EXPRESSION); if ( pNew.get() ) { switch(Token.nTokenType) { case SQL_LEVEL_1_TOKEN::OP_EXPRESSION: { if(IsTokenAboutProperty(Token, wszPropName)) { wmilib::auto_ptr<SQL_LEVEL_1_TOKEN> pToken(new SQL_LEVEL_1_TOKEN(Token)); if ( pToken.get() ) { pNew->AddToken(pToken.get()); pToken.release(); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } }
ExprStack.push(pNew.get()); pNew.release(); } break;
case SQL_LEVEL_1_TOKEN::TOKEN_AND: { if(ExprStack.size() < 2) { hres = WBEM_E_CRITICAL_ERROR; break; }
wmilib::auto_ptr<SQL_LEVEL_1_RPN_EXPRESSION> pFirst(ExprStack.top()); ExprStack.pop();
wmilib::auto_ptr<SQL_LEVEL_1_RPN_EXPRESSION> pSecond(ExprStack.top()); ExprStack.pop();
hres = AndQueryExpressions(pFirst.get(), pSecond.get(), pNew.get());
ExprStack.push(pNew.get()); pNew.release(); } break;
case SQL_LEVEL_1_TOKEN::TOKEN_OR: { if(ExprStack.size() < 2) { hres = WBEM_E_CRITICAL_ERROR; break; }
wmilib::auto_ptr<SQL_LEVEL_1_RPN_EXPRESSION> pFirst(ExprStack.top()); ExprStack.pop();
wmilib::auto_ptr<SQL_LEVEL_1_RPN_EXPRESSION> pSecond(ExprStack.top()); ExprStack.pop();
hres = OrQueryExpressions(pFirst.get(), pSecond.get(), pNew.get());
ExprStack.push(pNew.get()); pNew.release(); } break;
case SQL_LEVEL_1_TOKEN::TOKEN_NOT: { if(ExprStack.size() < 1) { hres = WBEM_E_CRITICAL_ERROR; break; }
wmilib::auto_ptr<SQL_LEVEL_1_RPN_EXPRESSION> pFirst(ExprStack.top()); ExprStack.pop();
// No information
ExprStack.push(pNew.get()); pNew.release(); } break;
default: { hres = WBEM_E_CRITICAL_ERROR; } break ; }
if(FAILED(hres)) { // An error occurred, break out of the loop
// ========================================
break; } } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } if(SUCCEEDED(hres) && ExprStack.size() != 1) { hres = WBEM_E_CRITICAL_ERROR; } if(FAILED(hres)) { return hres; // The guard will take care of stack
}
// All is good
// ===========
pNewExpr = ExprStack.top(); clearStack.Dismiss();
return S_OK; }
BOOL CQueryAnalyser::IsTokenAboutProperty (
IN SQL_LEVEL_1_TOKEN &Token, IN LPCWSTR wszPropName ) { return (wbem_wcsicmp(wszPropName, Token.pPropertyName) == 0); }
void CQueryAnalyser::AppendQueryExpression (
IN SQL_LEVEL_1_RPN_EXPRESSION *pDest, IN SQL_LEVEL_1_RPN_EXPRESSION *pSource ) { for(int i = 0; i < pSource->nNumTokens; i++) { SQL_LEVEL_1_TOKEN *pToken = new SQL_LEVEL_1_TOKEN(pSource->pArrayOfTokens[i]); if ( pToken ) { pDest->AddToken(pToken); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; } } }
HRESULT CQueryAnalyser::AndQueryExpressions (
IN SQL_LEVEL_1_RPN_EXPRESSION *pFirst, IN SQL_LEVEL_1_RPN_EXPRESSION *pSecond, OUT SQL_LEVEL_1_RPN_EXPRESSION *pNew ) { // If either one is empty, take the other
// ======================================
if(pFirst->nNumTokens == 0) { AppendQueryExpression(pNew, pSecond); return WBEM_S_NO_ERROR; }
if(pSecond->nNumTokens == 0) { AppendQueryExpression(pNew, pFirst); return WBEM_S_NO_ERROR; }
// Both are there --- and together
// ===============================
AppendQueryExpression(pNew, pFirst); AppendQueryExpression(pNew, pSecond);
SQL_LEVEL_1_TOKEN Token; Token.nTokenType = SQL_LEVEL_1_TOKEN::TOKEN_AND; SQL_LEVEL_1_TOKEN *pToken = new SQL_LEVEL_1_TOKEN(Token); if ( pToken ) { pNew->AddToken(pToken); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
return WBEM_S_NO_ERROR; }
HRESULT CQueryAnalyser::OrQueryExpressions (
IN SQL_LEVEL_1_RPN_EXPRESSION *pFirst, IN SQL_LEVEL_1_RPN_EXPRESSION *pSecond, OUT SQL_LEVEL_1_RPN_EXPRESSION *pNew ) { // If either one is empty, so is the result
// ======================================
if(pFirst->nNumTokens == 0 || pSecond->nNumTokens == 0) { return WBEM_S_NO_ERROR; }
// Both are there --- or together
// ==============================
AppendQueryExpression(pNew, pFirst); AppendQueryExpression(pNew, pSecond);
SQL_LEVEL_1_TOKEN Token; Token.nTokenType = SQL_LEVEL_1_TOKEN::TOKEN_OR; SQL_LEVEL_1_TOKEN *pToken = new SQL_LEVEL_1_TOKEN(Token); if ( pToken ) { pNew->AddToken(pToken); } else { throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ; }
return WBEM_S_NO_ERROR; }
HRESULT CQueryAnalyser::GetValuesForProp (
SQL_LEVEL_1_RPN_EXPRESSION *pExpr, LPCWSTR wszPropName, CHStringArray &awsVals ) { awsVals.RemoveAll();
// Get the necessary query
// =======================
SQL_LEVEL_1_RPN_EXPRESSION *pPropExpr = NULL ; HRESULT hres = CQueryAnalyser::GetNecessaryQueryForProperty (
pExpr, wszPropName, pPropExpr );
if(FAILED(hres)) { return hres; }
// See if there are any tokens
// ===========================
if(pPropExpr->nNumTokens == 0) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Combine them all
// ================
for(int i = 0; i < pPropExpr->nNumTokens; i++) { SQL_LEVEL_1_TOKEN& Token = pPropExpr->pArrayOfTokens[i]; switch ( Token.nTokenType ) { case SQL_LEVEL_1_TOKEN::TOKEN_NOT: { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; } break ;
case SQL_LEVEL_1_TOKEN::TOKEN_AND: case SQL_LEVEL_1_TOKEN::TOKEN_OR: {
// We treat them all as ORs
// ========================
} break;
default: { // This is a token
// ===============
if(Token.nOperator != SQL_LEVEL_1_TOKEN::OP_EQUAL) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Skip NULLs, but report them.
if (V_VT(&Token.vConstValue) == VT_NULL) { hres = WBEM_S_PARTIAL_RESULTS; continue; }
if(V_VT(&Token.vConstValue) != VT_BSTR) { delete pPropExpr; return WBEM_E_TYPE_MISMATCH; }
// This token is a string equality. Add the string to the list
// ===========================================================
awsVals.Add(CHString(V_BSTR(&Token.vConstValue))); } break ; } }
delete pPropExpr;
return hres; }
HRESULT CQueryAnalyser::GetValuesForProp (
SQL_LEVEL_1_RPN_EXPRESSION *pExpr, LPCWSTR wszPropName, std::vector<_bstr_t> &vectorVals ) { vectorVals.erase(vectorVals.begin(),vectorVals.end());
// Get the necessary query
// =======================
SQL_LEVEL_1_RPN_EXPRESSION *pPropExpr = NULL ; HRESULT hres = CQueryAnalyser::GetNecessaryQueryForProperty (
pExpr, wszPropName, pPropExpr );
if(FAILED(hres)) { return hres; }
// See if there are any tokens
// ===========================
if(pPropExpr->nNumTokens == 0) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Combine them all
// ================
for(int i = 0; i < pPropExpr->nNumTokens; i++) { SQL_LEVEL_1_TOKEN& Token = pPropExpr->pArrayOfTokens[i];
switch ( Token.nTokenType ) { case SQL_LEVEL_1_TOKEN::TOKEN_NOT: { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; } break ;
case SQL_LEVEL_1_TOKEN::TOKEN_AND: case SQL_LEVEL_1_TOKEN::TOKEN_OR: { // We treat them all as ORs
// ========================
} break ;
default: { // This is a token
// ===============
if(Token.nOperator != SQL_LEVEL_1_TOKEN::OP_EQUAL) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Skip NULLs, but report them.
if (V_VT(&Token.vConstValue) == VT_NULL) { hres = WBEM_S_PARTIAL_RESULTS; continue; }
if(V_VT(&Token.vConstValue) != VT_BSTR) { delete pPropExpr; return WBEM_E_INVALID_QUERY; }
// This token is a string equality. Add the string to the list
// ===========================================================
vectorVals.push_back(_bstr_t(V_BSTR(&Token.vConstValue))); } break ; } }
delete pPropExpr;
return hres; }
HRESULT CQueryAnalyser::GetValuesForProp (
SQL_LEVEL_1_RPN_EXPRESSION *pExpr, LPCWSTR wszPropName, std::vector<int> &vectorVals ) { vectorVals.erase(vectorVals.begin(),vectorVals.end());
// Get the necessary query
// =======================
SQL_LEVEL_1_RPN_EXPRESSION *pPropExpr = NULL ; HRESULT hres = CQueryAnalyser::GetNecessaryQueryForProperty (
pExpr, wszPropName, pPropExpr );
if(FAILED(hres)) { return hres; }
// See if there are any tokens
// ===========================
if(pPropExpr->nNumTokens == 0) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Combine them all
// ================
for(int i = 0; i < pPropExpr->nNumTokens; i++) { SQL_LEVEL_1_TOKEN &Token = pPropExpr->pArrayOfTokens[i]; switch ( Token.nTokenType ) { case SQL_LEVEL_1_TOKEN::TOKEN_NOT: { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; } break ;
case SQL_LEVEL_1_TOKEN::TOKEN_AND: case SQL_LEVEL_1_TOKEN::TOKEN_OR: { // We treat them all as ORs
// ========================
} break ;
default: { // This is a token
// ===============
if(Token.nOperator != SQL_LEVEL_1_TOKEN::OP_EQUAL) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Skip NULLs, but report them.
if (V_VT(&Token.vConstValue) == VT_NULL) { hres = WBEM_S_PARTIAL_RESULTS; continue; }
if(V_VT(&Token.vConstValue) != VT_I4) { delete pPropExpr; return WBEM_E_INVALID_QUERY; }
// This token is an int equality. Add the string to the list
// ===========================================================
vectorVals.push_back(V_I4(&Token.vConstValue)); } break ; } }
delete pPropExpr;
return hres; }
HRESULT CQueryAnalyser::GetValuesForProp (
SQL_LEVEL_1_RPN_EXPRESSION *pExpr, LPCWSTR wszPropName, std::vector<_variant_t> &vectorVals ) { vectorVals.erase(vectorVals.begin(),vectorVals.end());
// Get the necessary query
// =======================
SQL_LEVEL_1_RPN_EXPRESSION *pPropExpr = NULL ; HRESULT hres = CQueryAnalyser::GetNecessaryQueryForProperty (
pExpr, wszPropName, pPropExpr );
if(FAILED(hres)) { return hres; }
// See if there are any tokens
// ===========================
if(pPropExpr->nNumTokens == 0) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Combine them all
// ================
for(int i = 0; i < pPropExpr->nNumTokens; i++) { SQL_LEVEL_1_TOKEN &Token = pPropExpr->pArrayOfTokens[i]; switch ( Token.nTokenType ) { case SQL_LEVEL_1_TOKEN::TOKEN_NOT: { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; } break ;
case SQL_LEVEL_1_TOKEN::TOKEN_AND: case SQL_LEVEL_1_TOKEN::TOKEN_OR: { // We treat them all as ORs
// ========================
} break ;
default: { // This is a token
// ===============
if(Token.nOperator != SQL_LEVEL_1_TOKEN::OP_EQUAL) { delete pPropExpr; return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// This token is a string equality. Add the string to the list
// ===========================================================
vectorVals.push_back(_variant_t(Token.vConstValue)); } break ; } }
delete pPropExpr;
return WBEM_S_NO_ERROR; }
|