Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

537 lines
13 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
SQL1FILT.CPP
Abstract:
History:
--*/
#include "sql1filt.h"
void* CSql1Filter::GetInterface(REFIID riid)
{
if(riid == IID_IHmmFilter || riid == IID_IHmmSql1Filter)
return (IHmmSql1Filter*)&m_XFilter;
else if(riid == IID_IConfigureHmmSql1Filter)
return (IConfigureHmmSql1Filter*)&m_XConfigure;
else if(riid == IID_IHmmParse)
return (IHmmParse*)&m_XParse;
else
return NULL;
}
STDMETHODIMP CSql1Filter::XFilter::
IsSpecial()
{
if(m_pObject->m_apTokens.GetSize() == 0)
{
return HMM_S_ACCEPTS_EVERYTHING;
}
else
{
return HMM_S_FALSE;
}
}
STDMETHODIMP CSql1Filter::XFilter::
CheckObject(IN IHmmPropertySource* pSource,
OUT IHmmPropertyList** ppList, OUT IUnknown** ppHint)
{
if(ppHint) *ppHint = NULL;
return m_pObject->Evaluate(FALSE, pSource, ppList);
}
STDMETHODIMP CSql1Filter::XFilter::
GetType(IID* piid)
{
if(piid == NULL)
return HMM_E_INVALID_PARAMETER;
*piid = IID_IHmmSql1Filter;
return HMM_S_NO_ERROR;
}
STDMETHODIMP CSql1Filter::XFilter::
GetSelectedPropertyList(IN long lFlags, OUT IHmmPropertyList** ppList)
{
return m_pObject->m_TargetClass.GetSelected().QueryInterface(
IID_IHmmPropertyList,
(void**)ppList);
}
STDMETHODIMP CSql1Filter::XFilter::
GetTargetClass(OUT HMM_CLASS_INFO* pTargetClass)
{
if(pTargetClass == NULL)
return HMM_E_INVALID_PARAMETER;
m_pObject->m_XParse.EnsureTarget();
m_pObject->m_TargetClass.Save(*pTargetClass);
return HMM_S_NO_ERROR;
}
STDMETHODIMP CSql1Filter::XFilter::
GetTokens(IN long lFirstIndex, IN long lNumTokens, OUT long* plTokensReturned,
OUT HMM_SQL1_TOKEN* aTokens)
{
if(plTokensReturned == NULL || lNumTokens <= 0 || lFirstIndex < 0 ||
aTokens == NULL)
{
return HMM_E_INVALID_PARAMETER;
}
m_pObject->m_XParse.EnsureWhere();
long lHaveTokens = m_pObject->m_apTokens.GetSize();
if(lFirstIndex >= lHaveTokens)
{
*plTokensReturned = 0;
return HMM_S_NO_MORE_DATA;
}
long lGaveTokens = 0;
long lCurrentIndex = lFirstIndex;
while(lGaveTokens < lNumTokens && lCurrentIndex < lHaveTokens)
{
CSql1Token* pToken = m_pObject->m_apTokens[lCurrentIndex];
if(pToken->m_lTokenType != TOKENTYPE_SPECIAL)
{
pToken->Save(aTokens[lGaveTokens++]);
}
lCurrentIndex++;
}
*plTokensReturned = lGaveTokens;
return HMM_S_NO_ERROR;
}
//********************************* Configuration ******************************
STDMETHODIMP CSql1Filter::XConfigure::
SetTargetClass(IN HMM_CLASS_INFO* pTargetClass)
{
if(pTargetClass == NULL)
return HMM_E_INVALID_PARAMETER;
m_pObject->m_TargetClass.Load(*pTargetClass);
m_pObject->InvalidateTree();
return HMM_S_NO_ERROR;
}
STDMETHODIMP CSql1Filter::XConfigure::
AddTokens(IN long lNumTokens, IN HMM_SQL1_TOKEN* aTokens)
{
if(lNumTokens <= 0 || aTokens == NULL)
return HMM_E_INVALID_PARAMETER;
for(long l = 0; l < lNumTokens; l++)
{
m_pObject->m_apTokens.Add(new CSql1Token(aTokens[l]));
}
m_pObject->InvalidateTree();
return HMM_S_NO_ERROR;
}
STDMETHODIMP CSql1Filter::XConfigure::
RemoveAllTokens()
{
m_pObject->m_apTokens.RemoveAll();
m_pObject->InvalidateTree();
return HMM_S_NO_ERROR;
}
STDMETHODIMP CSql1Filter::XConfigure::
RemoveAllProperties()
{
return m_pObject->m_TargetClass.GetSelected().RemoveAllProperties();
}
STDMETHODIMP CSql1Filter::XConfigure::
AddProperties(IN long lNumProps, HMM_WSTR* awszProps)
{
return m_pObject->m_TargetClass.GetSelected().
AddProperties(lNumProps, awszProps);
}
//*********************************** Parsing *********************************
STDMETHODIMP CSql1Filter::XParse::
Parse(IN HMM_WSTR wszText, IN long lFlags)
{
delete m_pParser;
m_pParser = NULL;
if((lFlags & HMM_FLAG_LAZY) == 0)
{
m_wsText.Empty();
m_nStatus = not_parsing;
m_pObject->InvalidateTree();
CAbstractSql1Parser Parser(new CTextLexSource(wszText));
int nRes = Parser.Parse(this, CAbstractSql1Parser::FULL_PARSE);
m_InnerStack.Empty();
return ParserError(nRes);
}
else
{
m_wsText = wszText;
m_pParser = new CAbstractSql1Parser(new CTextLexSource((LPWSTR)m_wsText));
m_nStatus = at_0;
return HMM_S_NO_ERROR;
}
}
void CSql1Filter::XParse::SetClassName(LPCWSTR wszClass)
{
m_pObject->m_TargetClass.AccessClassName() = (LPWSTR)wszClass;
m_pObject->m_TargetClass.AccessIncludeChildren() = TRUE;
}
void CSql1Filter::XParse::AddToken(COPY const HMM_SQL1_TOKEN& Token)
{
m_pObject->m_apTokens.Add(new CSql1Token(Token));
if(Token.m_lTokenType == SQL1_OR || Token.m_lTokenType == SQL1_AND)
{
// Find the inner guy
// ==================
long lInnerIndex;
if(!m_InnerStack.Pop(lInnerIndex))
return;
V_I4(&m_pObject->m_apTokens[lInnerIndex]->m_vConstValue) =
m_pObject->m_apTokens.GetSize();
}
}
void CSql1Filter::XParse::AddProperty(COPY LPCWSTR wszProperty)
{
m_pObject->m_TargetClass.GetSelected().
AddProperties(1, (LPWSTR*)&wszProperty);
}
void CSql1Filter::XParse::AddAllProperties()
{
m_pObject->m_TargetClass.GetSelected().AddAllProperties();
}
void CSql1Filter::XParse::InOrder(long lOp)
{
/*
CSql1Token* pToken = new CSql1Token;
pToken->m_lTokenType = TOKENTYPE_SPECIAL;
pToken->m_lOperator = lOp;
V_I4(&pToken->m_vConstValue) = -1;
m_InnerStack.Push(m_pObject->m_apTokens.GetSize());
m_pObject->m_apTokens.Add(pToken);
*/
}
HRESULT CSql1Filter::XParse::EnsureTarget()
{
if(m_nStatus == at_0)
{
m_pObject->InvalidateTree();
int nRes = m_pParser->Parse(this, CAbstractSql1Parser::NO_WHERE);
m_nStatus = at_where;
return ParserError(nRes);
}
else return HMM_S_NO_ERROR;
}
HRESULT CSql1Filter::XParse::EnsureWhere()
{
if(m_nStatus == not_parsing)
{
return HMM_S_NO_ERROR;
}
else
{
m_pObject->InvalidateTree();
int nRes = m_pParser->Parse(this,
(m_nStatus == at_0)?CAbstractSql1Parser::FULL_PARSE
:CAbstractSql1Parser::JUST_WHERE);
m_InnerStack.Empty();
delete m_pParser;
m_pParser = NULL;
m_nStatus = not_parsing;
return ParserError(nRes);
}
}
HRESULT CSql1Filter::XParse::ParserError(int nRes)
{
switch(nRes)
{
case CAbstractSql1Parser::SUCCESS:
return HMM_S_NO_ERROR;
case CAbstractSql1Parser::SYNTAX_ERROR:
return HMM_E_INVALID_QUERY;
case CAbstractSql1Parser::LEXICAL_ERROR:
return HMM_E_INVALID_QUERY;
case CAbstractSql1Parser::FAILED:
return HMM_E_FAILED;
default:
return HMM_E_CRITICAL_ERROR;
}
}
CSql1Filter::XParse::~XParse()
{
delete m_pParser;
}
//*****************************************************************************
//*************************** Query Evaluator *********************************
//*****************************************************************************
//*****************************************************************************
//
// See sql1eveal.h for documentation
//
//*****************************************************************************
HRESULT CSql1Filter::Evaluate(BOOL bSkipTarget,
IN READ_ONLY IHmmPropertySource* pPropSource,
OUT IHmmPropertyList** ppList)
{
HRESULT hres;
GetTree();
if(m_pTree) m_pTree->Release();
if(ppList) *ppList = NULL;
hres = CHmmNode::EvaluateNode(m_pTree, pPropSource);
if(hres != HMM_S_NO_ERROR) return hres;
if(ppList)
{
m_TargetClass.GetSelected().QueryInterface(IID_IHmmPropertyList,
(void**)ppList);
}
return HMM_S_NO_ERROR;
if(!bSkipTarget)
{
// Check the class of the object
// =============================
hres = m_XParse.EnsureTarget();
if(FAILED(hres)) return hres;
CHmmClassInfo* pInfo = &m_TargetClass;
hres = CHmmClassInfo::CheckObjectAgainstMany(1, &pInfo,
pPropSource, ppList, NULL);
if(hres != HMM_S_NO_ERROR)
{
// Either an error or a simple class mismatch
// ==========================================
return hres;
}
}
// Now go for the expression
// =========================
hres = m_XParse.EnsureWhere();
if(FAILED(hres)) return hres;
int nNumTokens = m_apTokens.GetSize();
if(nNumTokens == 0)
{
// Empty query
// ===========
return HMM_S_NO_ERROR;
}
// Allocate boolean stack of appropriate length
// ============================================
CBooleanStack Stack(nNumTokens);
for(int nTokenIndex = 0; nTokenIndex < nNumTokens; nTokenIndex++)
{
CSql1Token* pToken = m_apTokens[nTokenIndex];
BOOL bVal1, bVal2;
switch(pToken->m_lTokenType)
{
case SQL1_AND:
// Pop the last two operands and AND them together
// ===============================================
if(!Stack.Pop(bVal1) || !Stack.Pop(bVal2))
{
return HMM_E_INVALID_QUERY;
}
Stack.Push(bVal1 && bVal2);
break;
case SQL1_OR:
// Pop the last two operands and OR them together
// ===============================================
if(!Stack.Pop(bVal1) || !Stack.Pop(bVal2))
{
return HMM_E_INVALID_QUERY;
}
Stack.Push(bVal1 || bVal2);
break;
case SQL1_NOT:
// Pop the last value and invert it
// ================================
if(!Stack.Pop(bVal1))
{
return HMM_E_INVALID_QUERY;
}
Stack.Push(!bVal1);
break;
case SQL1_OP_EXPRESSION:
// Evaluate the expression and push its value
// ==========================================
hres = pToken->Evaluate(pPropSource);
if(FAILED(hres)) return hres;
bVal1 = (hres == HMM_S_NO_ERROR);
Stack.Push(bVal1);
break;
case TOKENTYPE_SPECIAL:
if(!Stack.Pop(bVal1))
{
return HMM_E_INVALID_QUERY;
}
Stack.Push(bVal1);
if((pToken->m_lOperator == SQL1_OR && bVal1) ||
(pToken->m_lOperator == SQL1_AND && !bVal1))
{
nTokenIndex = V_I4(&pToken->m_vConstValue) - 1;
}
break;
}
}
// All tokens have been processed. There better be one element on the stack
// ========================================================================
BOOL bResult;
if(!Stack.Pop(bResult))
{
return HMM_E_INVALID_QUERY;
}
if(!Stack.IsEmpty())
{
return HMM_E_INVALID_QUERY;
}
if(bResult)
return HMM_S_NO_ERROR;
else
return HMM_S_FALSE;
}
CHmmNode* CSql1Filter::GetTree()
{
if(m_pTree != NULL)
{
m_pTree->AddRef();
return m_pTree;
}
// Construct the tree from the RPN
// ===============================
CUniquePointerStack<CHmmNode> aNodes(m_apTokens.GetSize());
CHmmNode* pNode1;
CHmmNode* pNode2;
CLogicalNode* pNewNode;
CSql1Token* pNewToken;
for(int i = 0; i < m_apTokens.GetSize(); i++)
{
CSql1Token* pToken = m_apTokens[i];
switch(pToken->m_lTokenType)
{
case SQL1_OR:
case SQL1_AND:
if(!aNodes.Pop(pNode2)) return NULL;
if(!aNodes.Pop(pNode1)) return NULL;
pNewNode = new CLogicalNode;
pNewNode->m_lTokenType = pToken->m_lTokenType;
pNewNode->Add(pNode1);
pNewNode->Add(pNode2);
aNodes.Push(pNewNode);
break;
case SQL1_NOT:
if(!aNodes.Pop(pNode1)) return NULL;
pNode1->Negate();
aNodes.Push(pNode1);
break;
case SQL1_OP_EXPRESSION:
pNewToken = new CSql1Token(*pToken);
aNodes.Push(pNewToken);
break;
default:
return NULL;
}
}
CHmmNode* pWhere;
if(!aNodes.Pop(pWhere))
{
if(i == 0)
pWhere = NULL;
else
return NULL;
}
if(!aNodes.IsEmpty()) return NULL;
// Add the class check
// ===================
CHmmNode* pTarget = m_TargetClass.GetTree();
CLogicalNode* pMain = new CLogicalNode;
pMain->m_lTokenType = SQL1_AND;
pMain->Add(pTarget);
pTarget->Release(); // Matching GetTree()
if(pWhere)
{
pMain->Add(pWhere);
}
m_pTree = pMain;
m_pTree->AddRef(); // for storage
m_pTree->AddRef(); // for return
m_pTree->Print(stdout, 0);
return m_pTree;
}