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.
 
 
 
 
 
 

703 lines
18 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
TREES.CPP
Abstract:
History:
--*/
#include <objbase.h>
#include "trees.h"
#include "hmmstr.h"
#include "stackt.h"
class CTreeInstruction
{
public:
enum {INST_PUSH = SQL1_OP_EXPRESSION,
INST_AND = SQL1_AND,
INST_OR = SQL1_OR
};
int m_nInst;
union
{
int m_nArg;
CHmmNode* m_pArg;
};
};
HRESULT CHmmNode::EvaluateNode(CHmmNode* pNode, IHmmPropertySource* pSource)
{
if(pNode == NULL) return HMM_S_NO_ERROR;
CHmmStack<CTreeInstruction> m_aInstructions(100);
BOOL bResult;
CTreeInstruction Inst;
Inst.m_nInst = CTreeInstruction::INST_PUSH;
Inst.m_pArg = pNode;
m_aInstructions.Push(Inst);
while(!m_aInstructions.IsEmpty())
{
CTreeInstruction Inst;
m_aInstructions.Pop(Inst);
int i;
int nCurrentPos;
int nNumChildren;
CHmmNode* pCurrentNode;
CLogicalNode* pLogNode;
switch(Inst.m_nInst)
{
case CTreeInstruction::INST_OR:
if(bResult)
{
m_aInstructions.PopToSize(Inst.m_nArg);
}
break;
case CTreeInstruction::INST_AND:
if(!bResult)
{
m_aInstructions.PopToSize(Inst.m_nArg);
}
break;
case CTreeInstruction::INST_PUSH:
pCurrentNode = Inst.m_pArg;
switch(pCurrentNode->m_lTokenType)
{
case SQL1_AND:
case SQL1_OR:
pLogNode = (CLogicalNode*)pCurrentNode;
nNumChildren = pLogNode->m_apChildren.GetSize();
nCurrentPos = m_aInstructions.GetSize();
for(i = nNumChildren-1; i >= 0; i--)
{
Inst.m_nInst = CTreeInstruction::INST_PUSH;
Inst.m_pArg = pLogNode->m_apChildren[i];
m_aInstructions.Push(Inst);
if(i != 0)
{
Inst.m_nInst = pLogNode->m_lTokenType;
Inst.m_nArg = nCurrentPos;
m_aInstructions.Push(Inst);
}
}
break;
default:
bResult = (pCurrentNode->Evaluate(pSource) == HMM_S_NO_ERROR);
break;
}
break;
}
}
if(bResult)
return HMM_S_NO_ERROR;
else
return HMM_S_FALSE;
}
void CHmmNode::PrintOffset(int nOffset)
{
for(int i = 0; i < nOffset; i++)
{
printf(" ");
}
}
HMM_RELATIONSHIP CHmmNode::RelateNodes(CHmmNode* pFirst, CHmmNode* pSecond,
CMetaData* pMeta)
{
if(pFirst->m_lTokenType == SQL1_OP_EXPRESSION)
{
if(pSecond->m_lTokenType == SQL1_OP_EXPRESSION)
{
// They can compare themselves
// ===========================
return CSql1Token::ComputeRelation((CSql1Token*)pFirst,
(CSql1Token*)pSecond, pMeta);
}
else
{
// Swap them to merge with the other case
// ======================================
HMM_RELATIONSHIP InverseRel = RelateNodes(pSecond, pFirst, pMeta);
return CRelationship::ReverseRoles(InverseRel);
}
}
else
{
// Relate to all the children of the first
// =======================================
CLogicalNode* pFirstLog = (CLogicalNode*)pFirst;
int nNumChildren = pFirstLog->m_apChildren.GetSize();
HMM_RELATIONSHIP* aChildRels = new HMM_RELATIONSHIP[nNumChildren];
for(int i = 0; i < nNumChildren; i++)
{
aChildRels[i] = RelateNodes(pFirstLog->m_apChildren[i], pSecond,
pMeta);
}
// Combine the results
// ===================
HMM_RELATIONSHIP nResult;
if(pFirstLog->m_lTokenType == SQL1_AND)
{
nResult = CRelationship::GetRelationshipOfFirstWithANDofSeconds(
nNumChildren, aChildRels);
}
else
{
nResult = CRelationship::GetRelationshipOfFirstWithORofSeconds(
nNumChildren, aChildRels);
}
delete [] aChildRels;
return nResult;
}
}
void CLogicalNode::Add(CHmmNode* pNode)
{
if(pNode == NULL)
return;
if(pNode->m_lTokenType != m_lTokenType)
{
m_apChildren.Add(pNode);
return;
}
// Copy the children
// =================
CLogicalNode* pLogNode = (CLogicalNode*)pNode;
for(int i = 0; i < pLogNode->m_apChildren.GetSize(); i++)
{
Add(pLogNode->m_apChildren[i]);
}
}
HRESULT CLogicalNode::Evaluate(IHmmPropertySource* pSource)
{
if(m_lTokenType == SQL1_AND)
{
for(int i = 0; i < m_apChildren.GetSize(); i++)
{
HRESULT hres = m_apChildren[i]->Evaluate(pSource);
if(hres != HMM_S_NO_ERROR) return hres;
}
return HMM_S_NO_ERROR;
}
else
{
for(int i = 0; i < m_apChildren.GetSize(); i++)
{
HRESULT hres = m_apChildren[i]->Evaluate(pSource);
if(hres != HMM_S_FALSE) return hres;
}
return HMM_S_NO_ERROR;
}
}
HRESULT CLogicalNode::Negate()
{
for(int i = 0; i < m_apChildren.GetSize(); i++)
{
HRESULT hres = m_apChildren[i]->Negate();
if(hres != HMM_S_FALSE) return hres;
}
if(m_lTokenType == SQL1_AND)
m_lTokenType = SQL1_OR;
else
m_lTokenType = SQL1_AND;
return HMM_S_NO_ERROR;
}
void CLogicalNode::Print(FILE* f, int nOffset)
{
PrintOffset(nOffset);
printf("%s\n", (m_lTokenType == SQL1_AND)?"AND":"OR");
for(int i = 0; i < m_apChildren.GetSize(); i++)
{
m_apChildren[i]->Print(f, nOffset+1);
}
}
CSql1Token::CSql1Token()
{
m_lTokenType = SQL1_OP_EXPRESSION;
VariantInit(&m_vConstValue);
}
CSql1Token::CSql1Token(const CSql1Token& Token)
{
m_lTokenType = Token.m_lTokenType;
if(m_lTokenType == SQL1_OP_EXPRESSION)
{
m_wsProperty = Token.m_wsProperty;
m_lOperator = Token.m_lOperator;
VariantInit(&m_vConstValue);
VariantCopy(&m_vConstValue, (VARIANT*)&Token.m_vConstValue);
m_lPropertyFunction = Token.m_lPropertyFunction;
m_lConstFunction = Token.m_lConstFunction;
}
}
CSql1Token::CSql1Token(const HMM_SQL1_TOKEN& Token)
{
VariantInit(&m_vConstValue);
Load(Token);
}
CSql1Token::~CSql1Token()
{
VariantClear(&m_vConstValue);
}
void CSql1Token::Load(const HMM_SQL1_TOKEN& Token)
{
m_lTokenType = Token.m_lTokenType;
if(m_lTokenType == SQL1_OP_EXPRESSION)
{
m_wsProperty = Token.m_wszProperty;
m_lOperator = Token.m_lOperator;
VariantCopy(&m_vConstValue, (VARIANT*)&Token.m_vConstValue);
m_lPropertyFunction = Token.m_lPropertyFunction;
m_lConstFunction = Token.m_lConstFunction;
}
}
void CSql1Token::Save(HMM_SQL1_TOKEN& Token)
{
Token.m_lTokenType = m_lTokenType;
if(m_lTokenType == SQL1_OP_EXPRESSION)
{
Token.m_wszProperty = HmmStringCopy(m_wsProperty);
Token.m_lOperator = m_lOperator;
VariantInit(&Token.m_vConstValue);
VariantCopy(&Token.m_vConstValue, &m_vConstValue);
Token.m_lPropertyFunction = m_lPropertyFunction;
Token.m_lConstFunction = m_lConstFunction;
}
else
{
Token.m_wszProperty = NULL;
VariantInit(&Token.m_vConstValue);
}
}
HRESULT CSql1Token::Evaluate(IHmmPropertySource* pPropSource)
{
HRESULT hres;
// Get the value of the property
// =============================
VARIANT vProperty;
VariantInit(&vProperty);
if(m_wsProperty.Length() == 0)
{
V_VT(&vProperty) = VT_UNKNOWN;
V_UNKNOWN(&vProperty) = pPropSource;
pPropSource->AddRef();
}
else if(FAILED(pPropSource->GetPropertyValue(m_wsProperty, 0,
&vProperty)))
{
return HMM_E_INSUFFICIENT_INFO;
}
if(V_VT(&vProperty) == VT_NULL)
{
return HMM_S_FALSE;
}
// Apply functions to property and constant
// ========================================
VARIANT vFinalProp;
VariantInit(&vFinalProp);
hres = EvaluateFunction(m_lPropertyFunction, &vProperty,
&vFinalProp);
VariantClear(&vProperty);
if(FAILED(hres)) return hres;
VARIANT vFinalConst;
VariantInit(&vFinalConst);
hres = EvaluateFunction(m_lConstFunction, &m_vConstValue, &vFinalConst);
if(FAILED(hres)) return hres;
// Handle ineritance
// =================
if(m_lOperator == SQL1_OPERATOR_INHERITSFROM)
{
if(V_VT(&vFinalProp) != VT_UNKNOWN || V_VT(&vFinalConst) != VT_BSTR)
return HMM_S_FALSE;
IHmmPropertySource* pProp = (IHmmPropertySource*)V_UNKNOWN(&vFinalProp);
hres = pProp->IsDerivedFrom(V_BSTR(&vFinalConst));
VariantClear(&vFinalConst);
VariantClear(&vFinalProp);
return hres;
}
else if(m_lOperator == SQL1_OPERATOR_NOTINHERITSFROM)
{
if(V_VT(&vFinalProp) != VT_UNKNOWN || V_VT(&vFinalConst) != VT_BSTR)
return HMM_S_FALSE;
IHmmPropertySource* pProp = (IHmmPropertySource*)V_UNKNOWN(&vFinalProp);
hres = pProp->IsDerivedFrom(V_BSTR(&vFinalConst));
VariantClear(&vFinalConst);
VariantClear(&vFinalProp);
return (hres == HMM_S_FALSE)?HMM_S_NO_ERROR : HMM_S_FALSE;
}
// Coerce the constant to the right type
// =====================================
if(FAILED(VariantChangeType(&vFinalConst, &vFinalConst, 0,
V_VT(&vFinalProp))))
{
// Fatal type mismatch --- expression == FALSE
VariantClear(&vFinalConst);
VariantClear(&vFinalProp);
return HMM_S_FALSE;
}
// Compare the two variants
// ========================
int nCompare = CompareVariants(vFinalProp, vFinalConst);
// Apply relational operator
// =========================
BOOL bResult;
switch(m_lOperator)
{
case SQL1_OPERATOR_EQUALS:
bResult = (nCompare == 0);
break;
case SQL1_OPERATOR_NOTEQUALS:
bResult = (nCompare != 0);
break;
case SQL1_OPERATOR_GREATEROREQUALS:
bResult = (nCompare >= 0);
break;
case SQL1_OPERATOR_LESSOREQUALS:
bResult = (nCompare <= 0);
break;
case SQL1_OPERATOR_GREATER:
bResult = (nCompare > 0);
break;
case SQL1_OPERATOR_LESS:
bResult = (nCompare < 0);
break;
default:
bResult = FALSE;
break;
}
VariantClear(&vFinalConst);
VariantClear(&vFinalProp);
if(bResult)
return HMM_S_NO_ERROR;
else
return HMM_S_FALSE;
}
int CSql1Token::CompareVariants(VARIANT& v1, VARIANT& v2)
{
switch(V_VT(&v2))
{
case VT_BSTR:
return wcscmp(V_BSTR(&v1), V_BSTR(&v2));
case VT_I4:
return V_I4(&v1) - V_I4(&v2);
case VT_I2:
return V_I2(&v1) - V_I2(&v2);
case VT_UI1:
return V_UI1(&v1) - V_UI1(&v2);
case VT_R4:
return (V_R4(&v1) > V_R4(&v2))?1:-1;
case VT_R8:
return (V_R8(&v1) > V_R8(&v2))?1:-1;
}
return 1;
}
HRESULT CSql1Token::EvaluateFunction(IN long lFunctionID,
IN READ_ONLY VARIANT* pvArg,
OUT INIT_AND_CLEAR_ME VARIANT* pvDest)
{
unsigned int nLen;
unsigned int i;
BSTR str;
switch(lFunctionID)
{
case SQL1_FUNCTION_UPPER:
if(V_VT(pvArg) != VT_BSTR)
{
return HMM_E_INVALID_QUERY;
}
VariantCopy(pvDest, pvArg);
str = V_BSTR(pvDest);
nLen = SysStringLen(str);
for(i = 0; i < nLen; i++)
{
str[i] = towupper(str[i]);
}
break;
case SQL1_FUNCTION_LOWER:
if(V_VT(pvArg) != VT_BSTR)
{
return HMM_E_INVALID_QUERY;
}
VariantCopy(pvDest, pvArg);
str = V_BSTR(pvDest);
nLen = SysStringLen(str);
for(i = 0; i < nLen; i++)
{
str[i] = towlower(str[i]);
}
break;
case SQL1_FUNCTION_NONE:
default:
VariantCopy(pvDest, pvArg);
break;
}
return HMM_S_NO_ERROR;
}
HRESULT CSql1Token::Negate()
{
switch(m_lOperator)
{
case SQL1_OPERATOR_EQUALS:
m_lOperator = SQL1_OPERATOR_NOTEQUALS;
break;
case SQL1_OPERATOR_NOTEQUALS:
m_lOperator = SQL1_OPERATOR_EQUALS;
break;
case SQL1_OPERATOR_GREATEROREQUALS:
m_lOperator = SQL1_OPERATOR_LESS;
break;
case SQL1_OPERATOR_LESSOREQUALS:
m_lOperator = SQL1_OPERATOR_GREATER;
break;
case SQL1_OPERATOR_GREATER:
m_lOperator = SQL1_OPERATOR_LESSOREQUALS;
break;
case SQL1_OPERATOR_LESS:
m_lOperator = SQL1_OPERATOR_GREATEROREQUALS;
break;
case SQL1_OPERATOR_LIKE:
m_lOperator = SQL1_OPERATOR_UNLIKE;
break;
case SQL1_OPERATOR_UNLIKE:
m_lOperator = SQL1_OPERATOR_LIKE;
break;
case SQL1_OPERATOR_INHERITSFROM:
m_lOperator = SQL1_OPERATOR_NOTINHERITSFROM;
break;
case SQL1_OPERATOR_NOTINHERITSFROM:
m_lOperator = SQL1_OPERATOR_INHERITSFROM;
break;
default:
return HMM_E_FAILED;
}
return HMM_S_NO_ERROR;
}
#define HMM_SMALL -100
#define HMM_LARGE 100
HMM_RELATIONSHIP CSql1Token::ComputeRelation(CSql1Token* pFirst,
CSql1Token* pSecond,
CMetaData* pMeta)
{
if(!pFirst->m_wsProperty.EqualNoCase(pSecond->m_wsProperty))
{
// TBD: the case of INHERITSFROM versus __CLASS== needs to be handled
// here. Ignore for now, since SQL1 does not support it.
// ==================================================================
return RELATION_NONE;
}
if(pFirst->m_lOperator == SQL1_OPERATOR_LIKE ||
pFirst->m_lOperator == SQL1_OPERATOR_UNLIKE ||
pSecond->m_lOperator == SQL1_OPERATOR_LIKE ||
pSecond->m_lOperator == SQL1_OPERATOR_UNLIKE)
{
return RELATION_NONE;
}
BOOL bFirstAboutInheritance =
(pFirst->m_lOperator == SQL1_OPERATOR_INHERITSFROM ||
pFirst->m_lOperator == SQL1_OPERATOR_NOTINHERITSFROM);
BOOL bSecondAboutInheritance =
(pSecond->m_lOperator == SQL1_OPERATOR_INHERITSFROM ||
pSecond->m_lOperator == SQL1_OPERATOR_NOTINHERITSFROM);
if(bFirstAboutInheritance != bSecondAboutInheritance)
{
return RELATION_NONE;
}
if(bFirstAboutInheritance && bSecondAboutInheritance)
{
// Both talk about inhertance
// ==========================
int nClassRel = pMeta->GetClassRelation(V_BSTR(&pFirst->m_vConstValue),
V_BSTR(&pSecond->m_vConstValue));
BOOL bFirstIn =
(pFirst->m_lOperator == SQL1_OPERATOR_INHERITSFROM);
BOOL bSecondIn =
(pSecond->m_lOperator == SQL1_OPERATOR_INHERITSFROM);
switch(nClassRel)
{
case SEPARATE_BRANCHES:
// It can't be in both.
return (HMM_RELATIONSHIP)
(RELATION_NONE - CTwoValues::Combine(bFirstIn, bSecondIn));
case FIRST_IS_PARENT:
// If it's in second, it's in first
return (HMM_RELATIONSHIP)
(RELATION_NONE - CTwoValues::Combine(!bFirstIn, bSecondIn));
case SECOND_IS_PARENT:
// If it's in first, it's in second
return (HMM_RELATIONSHIP)
(RELATION_NONE - CTwoValues::Combine(bFirstIn, !bSecondIn));
}
}
// None talk about inhertiance
// ===========================
int nCompare = CompareVariants(pFirst->m_vConstValue,
pSecond->m_vConstValue);
// Assume that the first constant is 0, and the second is nCompare*5.
// =================================================================
// Compute the segment for X based on the first token
// ==================================================
int nFirstStart, nFirstEnd;
ComputeSegment(pFirst->m_lOperator, 0, nFirstStart, nFirstEnd);
int nSecondStart, nSecondEnd;
ComputeSegment(pSecond->m_lOperator, nCompare*5, nSecondStart, nSecondEnd);
int nRelation = 0;
if(nFirstStart <= nSecondEnd && nSecondStart <= nFirstEnd)
nRelation += VALUE_BOTH_TRUE;
if(nFirstStart < nSecondStart || nFirstEnd > nSecondEnd)
nRelation += VALUE_ONLY_FIRST;
if(nSecondStart < nFirstStart || nSecondEnd > nFirstEnd)
nRelation += VALUE_ONLY_SECOND;
if((nFirstStart > HMM_SMALL && nSecondStart > HMM_SMALL) ||
(nFirstEnd < HMM_LARGE && nSecondEnd < HMM_LARGE))
nRelation += VALUE_BOTH_FALSE;
return (HMM_RELATIONSHIP)nRelation;
}
void CSql1Token::ComputeSegment(long lOperator, int nRightHand,
int& nStart, int& nEnd)
{
switch(lOperator)
{
case SQL1_OPERATOR_EQUALS:
nStart = nEnd = nRightHand;
return;
case SQL1_OPERATOR_NOTEQUALS:// TBD --- at this point a NOOP
nStart = HMM_SMALL;
nStart = HMM_LARGE;
return;
case SQL1_OPERATOR_LESS:
nStart = HMM_SMALL;
nEnd = nRightHand - 1;
return;
case SQL1_OPERATOR_LESSOREQUALS:
nStart = HMM_SMALL;
nEnd = nRightHand;
return;
case SQL1_OPERATOR_GREATER:
nStart = nRightHand + 1;
nEnd = HMM_LARGE;
case SQL1_OPERATOR_GREATEROREQUALS:
nStart = nRightHand;
nEnd = HMM_LARGE;
default:
nStart = HMM_SMALL;
nStart = HMM_LARGE;
return;
}
}
void CSql1Token::Print(FILE* f, int nOffset)
{
PrintOffset(nOffset);
printf("EXP\n");
PrintOffset(nOffset+1);
printf("Property: %S\n", m_wsProperty);
PrintOffset(nOffset+1);
printf("Property function: %d\n", m_lPropertyFunction);
PrintOffset(nOffset+1);
printf("Operator: %d\n", m_lOperator);
PrintOffset(nOffset+1);
printf("Constant: ");
switch(V_VT(&m_vConstValue))
{
case VT_BSTR:
printf("%S", V_BSTR(&m_vConstValue)); break;
case VT_I4:case VT_I2:case VT_UI1:
printf("%d", V_I4(&m_vConstValue)); break;
case VT_R4: case VT_R8:
printf("%f", V_R8(&m_vConstValue)); break;
default:
printf("error");
}
printf("\n");
PrintOffset(nOffset+1);
printf("Constant function: %d\n", m_lConstFunction);
}