703 lines
18 KiB
C++
703 lines
18 KiB
C++
|
/*++
|
||
|
|
||
|
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);
|
||
|
}
|