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.
 
 
 
 
 
 

2414 lines
62 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
QL.CPP
Abstract:
Level 1 Syntax QL Parser
Implements the syntax described in QL_1.BNF. This translates the input
into an RPN stream of tokens.
History:
a-raymcc 21-Jun-96 Created.
mdavis 23-Apr-99 Changed to allow 'group' as a property name
for Raid 47767. Also fixed GetText() for
property comparisons and improved Dump().
--*/
#include "precomp.h"
#include <stdio.h>
#include <errno.h>
#include <math.h>
#include <corepol.h>
#include <genlex.h>
#include <qllex.h>
#include <ql.h>
//#include <wbemstr.h>
#include <wbemcomn.h>
#include <wbemutil.h>
#include <genutils.h>
#include <corex.h>
#define trace(x) //printf x
WBEM_WSTR WbemStringAlloc(unsigned long lNumChars)
{
return (WBEM_WSTR)CoTaskMemAlloc(lNumChars+1);
}
void WbemStringFree(WBEM_WSTR String)
{
CoTaskMemFree(String);
}
unsigned long WbemStringLen(const WCHAR* String)
{
return wcslen(String);
}
WBEM_WSTR WbemStringCopy(const WCHAR* String)
{
if(String == NULL) return NULL;
WBEM_WSTR NewString = (WBEM_WSTR)CoTaskMemAlloc(2*(wcslen(String)+1));
if(NewString == NULL) return NULL;
wcscpy(NewString, String);
return NewString;
}
//***************************************************************************
//
// WCHARToDOUBLE
//
// Converts a wchar to a double, but does it using the english locale rather
// than whatever local the process is running in. This allows us to support
// all english queries even on German machines.
//
//***************************************************************************
DOUBLE WCHARToDOUBLE(WCHAR * pConv, bool & bSuccess)
{
bSuccess = false;
if(pConv == NULL)
return 0.0;
VARIANT varTo, varFrom;
VariantInit(&varTo);
varFrom.vt = VT_BSTR;
varFrom.bstrVal = SysAllocString(pConv);
if ( varFrom.bstrVal == NULL )
{
return 0.0;
}
SCODE sc = VariantChangeTypeEx(&varTo, &varFrom, 0x409, 0, VT_R8);
SysFreeString(varFrom.bstrVal);
if ( FAILED(sc) )
{
return 0.0;
}
bSuccess = true;
return varTo.dblVal;
}
CPropertyName::CPropertyName(const CPropertyName& Other)
{
Init();
*this = Other;
}
void CPropertyName::Init()
{
m_lNumElements = 0;
m_lAllocated = 0;
m_aElements = NULL;
m_pvHandle = NULL;
}
void CPropertyName::operator=(const CPropertyName& Other)
{
*this = (const WBEM_PROPERTY_NAME&)Other;
m_pvHandle = Other.m_pvHandle;
}
void CPropertyName::operator=(const WBEM_PROPERTY_NAME& Other)
{
Empty();
if ( Other.m_lNumElements > 0)
{
m_aElements = new WBEM_NAME_ELEMENT[Other.m_lNumElements];
if ( m_aElements == NULL )
{
throw CX_MemoryException();
}
}
m_lAllocated = Other.m_lNumElements;
for( long l=0 ; l < Other.m_lNumElements; l++ )
{
if(Other.m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY)
{
m_aElements[l].Element.m_wszPropertyName =
WbemStringCopy(Other.m_aElements[l].Element.m_wszPropertyName);
if ( m_aElements[l].Element.m_wszPropertyName == NULL )
{
break;
}
}
else
{
m_aElements[l].Element.m_lArrayIndex =
Other.m_aElements[l].Element.m_lArrayIndex;
}
m_aElements[l].m_nType = Other.m_aElements[l].m_nType;
}
m_lNumElements = l;
if ( m_lNumElements != Other.m_lNumElements )
{
throw CX_MemoryException();
}
}
BOOL CPropertyName::operator==(const WBEM_PROPERTY_NAME& Other)
{
if(m_lNumElements != Other.m_lNumElements)
return FALSE;
for(long l = 0; l < m_lNumElements; l++)
{
if(m_aElements[l].m_nType != Other.m_aElements[l].m_nType)
return FALSE;
if(m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY)
{
if(wbem_wcsicmp(m_aElements[l].Element.m_wszPropertyName,
Other.m_aElements[l].Element.m_wszPropertyName))
{
return FALSE;
}
}
else
{
if(m_aElements[l].Element.m_lArrayIndex !=
Other.m_aElements[l].Element.m_lArrayIndex)
{
return FALSE;
}
}
}
return TRUE;
}
void CPropertyName::Empty()
{
if ( m_aElements!=NULL )
{
for(long l = 0; l < m_lNumElements; l++)
{
if(m_aElements[l].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY)
{
WbemStringFree(m_aElements[l].Element.m_wszPropertyName);
}
}
delete [] m_aElements;
m_aElements = NULL;
}
m_lNumElements = 0;
m_lAllocated = 0;
m_pvHandle = NULL;
}
LPCWSTR CPropertyName::GetStringAt(long lIndex) const
{
if(m_aElements[lIndex].m_nType == WBEM_NAME_ELEMENT_TYPE_PROPERTY)
{
return m_aElements[lIndex].Element.m_wszPropertyName;
}
else return NULL;
}
void CPropertyName::AddElement(LPCWSTR wszElement)
{
EnsureAllocated(m_lNumElements+1);
LPWSTR wszTemp = WbemStringCopy(wszElement);
if ( wszTemp == NULL )
{
throw CX_MemoryException();
}
m_aElements[m_lNumElements].m_nType = WBEM_NAME_ELEMENT_TYPE_PROPERTY;
m_aElements[m_lNumElements].Element.m_wszPropertyName = wszTemp;
m_lNumElements++;
}
void CPropertyName::EnsureAllocated(long lElements)
{
if(m_lAllocated < lElements)
{
m_lAllocated = lElements+5;
WBEM_NAME_ELEMENT* pTemp = new WBEM_NAME_ELEMENT[m_lAllocated];
if (!pTemp)
throw CX_MemoryException();
memcpy(pTemp, m_aElements, sizeof(WBEM_NAME_ELEMENT) * m_lNumElements);
delete [] m_aElements;
m_aElements = pTemp;
}
}
DELETE_ME LPWSTR CPropertyName::GetText()
{
WString wsText;
for(int i = 0; i < m_lNumElements; i++)
{
if(m_aElements[i].m_nType != WBEM_NAME_ELEMENT_TYPE_PROPERTY)
return NULL;
if(i > 0)
wsText += L".";
wsText += m_aElements[i].Element.m_wszPropertyName;
}
return wsText.UnbindPtr();
}
//***************************************************************************
//***************************************************************************
DWORD CAbstractQl1Parser::TranslateIntrinsic(LPCWSTR pFuncName)
{
if (wbem_wcsicmp(pFuncName, L"UPPER") == 0)
return QL1_FUNCTION_UPPER;
if (wbem_wcsicmp(pFuncName, L"LOWER") == 0)
return QL1_FUNCTION_LOWER;
return QL1_FUNCTION_NONE;
}
void CAbstractQl1Parser::InitToken(WBEM_QL1_TOKEN* pToken)
{
pToken->m_lTokenType = QL1_NONE;
pToken->m_PropertyName.m_lNumElements = 0;
pToken->m_PropertyName.m_aElements = NULL;
pToken->m_PropertyName2.m_lNumElements = 0;
pToken->m_PropertyName2.m_aElements = NULL;
VariantInit(&pToken->m_vConstValue);
}
CAbstractQl1Parser::CAbstractQl1Parser(CGenLexSource *pSrc)
{
m_pLexer = new CGenLexer(Ql_1_LexTable, pSrc);
if ( m_pLexer == NULL )
{
throw CX_MemoryException();
}
m_nLine = 0;
m_pTokenText = 0;
m_nCurrentToken = 0;
// Semantic transfer variables.
// ============================
m_nRelOp = 0;
VariantInit(&m_vTypedConst);
m_dwPropFunction = 0;
m_dwConstFunction = 0;
m_PropertyName.m_lNumElements = 0;
m_PropertyName.m_aElements = NULL;
m_PropertyName2.m_lNumElements = 0;
m_PropertyName2.m_aElements = NULL;
m_bPropComp = FALSE;
}
CAbstractQl1Parser::~CAbstractQl1Parser()
{
VariantClear(&m_vTypedConst);
DeletePropertyName();
delete m_pLexer;
}
int CAbstractQl1Parser::Parse(CQl1ParseSink* pSink, int nFlags)
{
m_pSink = pSink;
int nRes = parse(nFlags);
m_pSink = NULL;
return nRes;
}
//***************************************************************************
//
// Next()
//
// Advances to the next token and recognizes keywords, etc.
//
//***************************************************************************
BOOL CAbstractQl1Parser::Next(int nFlags)
{
m_nCurrentToken = m_pLexer->NextToken();
if (m_nCurrentToken == QL_1_TOK_ERROR)
return FALSE;
m_nLine = m_pLexer->GetLineNum();
m_pTokenText = m_pLexer->GetTokenText();
if (m_nCurrentToken == QL_1_TOK_EOF)
m_pTokenText = L"<end of file>";
// Keyword check.
// ==============
if (m_nCurrentToken == QL_1_TOK_IDENT && nFlags != NO_KEYWORDS)
{
if (wbem_wcsicmp(m_pTokenText, L"select") == 0)
m_nCurrentToken = QL_1_TOK_SELECT;
else if (wbem_wcsicmp(m_pTokenText, L"from") == 0)
m_nCurrentToken = QL_1_TOK_FROM;
else if (wbem_wcsicmp(m_pTokenText, L"where") == 0)
m_nCurrentToken = QL_1_TOK_WHERE;
else if (wbem_wcsicmp(m_pTokenText, L"like") == 0)
m_nCurrentToken = QL_1_TOK_LIKE;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"or") == 0)
m_nCurrentToken = QL_1_TOK_OR;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"and") == 0)
m_nCurrentToken = QL_1_TOK_AND;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"not") == 0)
m_nCurrentToken = QL_1_TOK_NOT;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"IS") == 0)
m_nCurrentToken = QL_1_TOK_IS;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"NULL") == 0)
m_nCurrentToken = QL_1_TOK_NULL;
else if (wbem_wcsicmp(m_pTokenText, L"WITHIN") == 0)
m_nCurrentToken = QL_1_TOK_WITHIN;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"ISA") == 0)
m_nCurrentToken = QL_1_TOK_ISA;
else if (nFlags != EXCLUDE_GROUP_KEYWORD && wbem_wcsicmp(m_pTokenText, L"GROUP") == 0)
m_nCurrentToken = QL_1_TOK_GROUP;
else if (wbem_wcsicmp(m_pTokenText, L"BY") == 0)
m_nCurrentToken = QL_1_TOK_BY;
else if (wbem_wcsicmp(m_pTokenText, L"HAVING") == 0)
m_nCurrentToken = QL_1_TOK_HAVING;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"TRUE") == 0)
m_nCurrentToken = QL_1_TOK_TRUE;
else if (nFlags != EXCLUDE_EXPRESSION_KEYWORDS && wbem_wcsicmp(m_pTokenText, L"FALSE") == 0)
m_nCurrentToken = QL_1_TOK_FALSE;
}
return TRUE;
}
LPCWSTR CAbstractQl1Parser::GetSinglePropertyName()
{
if(m_PropertyName.m_lNumElements < 1)
return NULL;
if(m_PropertyName.m_aElements[0].m_nType != WBEM_NAME_ELEMENT_TYPE_PROPERTY)
return NULL;
return m_PropertyName.m_aElements[0].Element.m_wszPropertyName;
}
void CAbstractQl1Parser::DeletePropertyName()
{
for(long l = 0; l < m_PropertyName.m_lNumElements; l++)
{
if(m_PropertyName.m_aElements[l].m_nType ==
WBEM_NAME_ELEMENT_TYPE_PROPERTY)
{
WbemStringFree(m_PropertyName.m_aElements[l].
Element.m_wszPropertyName);
}
}
delete [] m_PropertyName.m_aElements;
m_PropertyName.m_lNumElements = 0;
m_PropertyName.m_aElements = NULL;
}
int CAbstractQl1Parser::FlipOperator(int nOp)
{
switch(nOp)
{
case QL1_OPERATOR_EQUALS:
return QL1_OPERATOR_EQUALS;
case QL1_OPERATOR_NOTEQUALS:
return QL1_OPERATOR_NOTEQUALS;
case QL1_OPERATOR_GREATER:
return QL1_OPERATOR_LESS;
case QL1_OPERATOR_LESS:
return QL1_OPERATOR_GREATER;
case QL1_OPERATOR_LESSOREQUALS:
return QL1_OPERATOR_GREATEROREQUALS;
case QL1_OPERATOR_GREATEROREQUALS:
return QL1_OPERATOR_LESSOREQUALS;
case QL1_OPERATOR_LIKE:
return QL1_OPERATOR_LIKE;
case QL1_OPERATOR_UNLIKE:
return QL1_OPERATOR_UNLIKE;
case QL1_OPERATOR_ISA:
return QL1_OPERATOR_INV_ISA;
case QL1_OPERATOR_ISNOTA:
return QL1_OPERATOR_INV_ISNOTA;
case QL1_OPERATOR_INV_ISA:
return QL1_OPERATOR_ISA;
case QL1_OPERATOR_INV_ISNOTA:
return QL1_OPERATOR_ISNOTA;
default:
return nOp;
}
}
void CAbstractQl1Parser::AddAppropriateToken(const WBEM_QL1_TOKEN& Token)
{
if(m_bInAggregation)
m_pSink->AddHavingToken(Token);
else
m_pSink->AddToken(Token);
}
//***************************************************************************
//
// <parse> ::= SELECT <prop_list> FROM <classname> WHERE <expr>;
//
//***************************************************************************
// ok
int CAbstractQl1Parser::parse(int nFlags)
{
int nRes;
m_bInAggregation = FALSE;
if(nFlags != JUST_WHERE)
{
m_pLexer->Reset();
// SELECT
// ======
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken != QL_1_TOK_SELECT)
return SYNTAX_ERROR;
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
// <prop_list>
// ===========
if (nRes = prop_list())
return nRes;
// FROM
// ====
if (m_nCurrentToken != QL_1_TOK_FROM)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
// <classname>
// ===========
if (nRes = class_name())
return nRes;
// <tolerance>
// ===========
if(nRes = tolerance())
return nRes;
}
if(nFlags != NO_WHERE)
{
// WHERE clause.
// =============
if(nRes = opt_where())
return nRes;
// GROUP BY clause
// ===============
if(nRes = opt_aggregation())
return nRes;
}
return SUCCESS;
}
//***************************************************************************
//
// <opt_where> ::= WHERE <expr>;
// <opt_where> ::= <>;
//
//***************************************************************************
int CAbstractQl1Parser::opt_where()
{
int nRes;
if (m_nCurrentToken == QL_1_TOK_EOF || m_nCurrentToken == QL_1_TOK_GROUP)
{
trace(("No WHERE clause\n"));
return SUCCESS;
}
if (m_nCurrentToken != QL_1_TOK_WHERE)
return SYNTAX_ERROR;
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
// <expr>
// ======
if (nRes = expr())
return nRes;
// Verify that the current token is QL_1_TOK_EOF.
// ===============================================
if (m_nCurrentToken != QL_1_TOK_EOF && m_nCurrentToken != QL_1_TOK_GROUP)
return SYNTAX_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <prop_list> ::= <property_name> <prop_list_2>;
//
//***************************************************************************
int CAbstractQl1Parser::prop_list()
{
int nRes;
if (m_nCurrentToken != QL_1_TOK_ASTERISK &&
m_nCurrentToken != QL_1_TOK_IDENT)
return SYNTAX_ERROR;
if (nRes = property_name())
return nRes;
return prop_list_2();
}
//***************************************************************************
//
// <prop_list_2> ::= COMMA <prop_list>;
// <prop_list_2> ::= <>;
//
//***************************************************************************
int CAbstractQl1Parser::prop_list_2()
{
if (m_nCurrentToken == QL_1_TOK_COMMA)
{
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
return prop_list();
}
return SUCCESS;
}
int CAbstractQl1Parser::parse_property_name(CPropertyName& Prop)
{
int nCount = 0;
Prop.Empty();
try
{
while(m_nCurrentToken == QL_1_TOK_IDENT)
{
// VERY TEMPORARY: See if this is a count query
// that should be forwarded to the repository.
BOOL bSkipNext = FALSE;
if (!_wcsicmp(L"count", m_pTokenText))
{
if (Next() && m_nCurrentToken == QL_1_TOK_OPEN_PAREN)
{
if (!Next() || m_nCurrentToken != QL_1_TOK_ASTERISK)
return LEXICAL_ERROR;
if (!Next() || m_nCurrentToken != QL_1_TOK_CLOSE_PAREN)
return LEXICAL_ERROR;
Prop.AddElement(L"count(*)");
m_pSink->SetCountQuery();
}
else
{
bSkipNext = TRUE;
Prop.AddElement(L"count");
}
}
else
Prop.AddElement(m_pTokenText);
nCount++;
if (!bSkipNext)
{
if(!Next())
return LEXICAL_ERROR;
}
if(m_nCurrentToken != QL_1_TOK_DOT)
break;
if(!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
}
}
catch (CX_MemoryException)
{
return OUT_OF_MEMORY;
}
catch (...)
{
return FAILED;
}
if (nCount)
return SUCCESS;
else
return SYNTAX_ERROR;
}
//***************************************************************************
//
// <property_name> ::= PROPERTY_NAME_STRING;
// <property_name> ::= ASTERISK;
//
//***************************************************************************
int CAbstractQl1Parser::property_name()
{
try
{
if (m_nCurrentToken == QL_1_TOK_ASTERISK)
{
trace(("Asterisk\n"));
if(m_bInAggregation)
m_pSink->AddAllAggregationProperties();
else
m_pSink->AddAllProperties();
if(!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
// Else a list of property names
// =============================
CPropertyName Prop;
int nRes = parse_property_name(Prop);
if(nRes != SUCCESS)
return nRes;
if(m_bInAggregation)
m_pSink->AddAggregationProperty(Prop);
else
m_pSink->AddProperty(Prop);
}
catch (CX_MemoryException)
{
return OUT_OF_MEMORY;
}
catch (...)
{
return FAILED;
}
return SUCCESS;
}
//***************************************************************************
//
// <classname> ::= CLASS_NAME_STRING;
//
//***************************************************************************
int CAbstractQl1Parser::class_name()
{
if (m_nCurrentToken != QL_1_TOK_IDENT)
return SYNTAX_ERROR;
trace(("Class name is %S\n", m_pTokenText));
m_pSink->SetClassName(m_pTokenText);
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <tolerance> ::= <>;
// <tolerance> ::= WITHIN duration;
//
//***************************************************************************
int CAbstractQl1Parser::tolerance()
{
LPWSTR wszGarbage;
WBEM_QL1_TOLERANCE Tolerance;
if(m_nCurrentToken != QL_1_TOK_WITHIN)
{
Tolerance.m_bExact = TRUE;
m_pSink->SetTolerance(Tolerance);
return SUCCESS;
}
if(!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken == QL_1_TOK_REAL)
{
Tolerance.m_bExact = FALSE;
bool bSuccess;
Tolerance.m_fTolerance = WCHARToDOUBLE(m_pTokenText, bSuccess);
if(Tolerance.m_fTolerance <= 0 || bSuccess == false)
{
return SYNTAX_ERROR;
}
m_pSink->SetTolerance(Tolerance);
Next();
return SUCCESS;
}
else if (m_nCurrentToken == QL_1_TOK_INT)
{
Tolerance.m_bExact = FALSE;
Tolerance.m_fTolerance = wcstol(m_pTokenText, &wszGarbage, 10);
if(Tolerance.m_fTolerance < 0)
{
return SYNTAX_ERROR;
}
m_pSink->SetTolerance(Tolerance);
Next();
return SUCCESS;
}
else
{
return SYNTAX_ERROR;
}
}
//***************************************************************************
//
// <expr> ::= <term> <expr2>;
//
//***************************************************************************
int CAbstractQl1Parser::expr()
{
int nRes;
if (nRes = term())
return nRes;
if (nRes = expr2())
return nRes;
return SUCCESS;
}
//***************************************************************************
//
// <expr2> ::= OR <term> <expr2>;
// <expr2> ::= <>;
//
// Entry: Assumes token OR already current.
// Exit: Advances a token
//
//***************************************************************************
int CAbstractQl1Parser::expr2()
{
int nRes;
while (1)
{
if (m_nCurrentToken == QL_1_TOK_OR)
{
trace(("Token OR\n"));
m_pSink->InOrder(QL1_OR);
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
if (nRes = term())
return nRes;
WBEM_QL1_TOKEN NewTok;
InitToken(&NewTok);
NewTok.m_lTokenType = QL1_OR;
AddAppropriateToken(NewTok);
}
else break;
}
return SUCCESS;
}
//***************************************************************************
//
// <term> ::= <simple_expr> <term2>;
//
//***************************************************************************
int CAbstractQl1Parser::term()
{
int nRes;
if (nRes = simple_expr())
return nRes;
if (nRes = term2())
return nRes;
return SUCCESS;
}
//***************************************************************************
//
// <term2> ::= AND <simple_expr> <term2>;
// <term2> ::= <>;
//
//***************************************************************************
int CAbstractQl1Parser::term2()
{
int nRes;
while (1)
{
if (m_nCurrentToken == QL_1_TOK_AND)
{
trace(("Token AND\n"));
m_pSink->InOrder(QL1_AND);
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
if (nRes = simple_expr())
return nRes;
// Add the AND token.
// ==================
WBEM_QL1_TOKEN NewTok;
InitToken(&NewTok);
NewTok.m_lTokenType = QL1_AND;
AddAppropriateToken(NewTok);
}
else break;
}
return SUCCESS;
}
//***************************************************************************
//
// <simple_expr> ::= NOT <expr>;
// <simple_expr> ::= OPEN_PAREN <expr> CLOSE_PAREN;
// <simple_expr> ::= IDENTIFIER <leading_ident_expr> <finalize>;
// <simple_expr> ::= VARIANT <rel_operator> <trailing_prop_expr> <finalize>;
//
//***************************************************************************
// ok
int CAbstractQl1Parser::simple_expr()
{
int nRes;
// NOT <expr>
// ==========
if (m_nCurrentToken == QL_1_TOK_NOT)
{
trace(("Operator NOT\n"));
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
if (nRes = simple_expr())
return nRes;
WBEM_QL1_TOKEN NewTok;
InitToken(&NewTok);
NewTok.m_lTokenType = QL1_NOT;
AddAppropriateToken(NewTok);
return SUCCESS;
}
// OPEN_PAREN <expr> CLOSE_PAREN
// =============================
else if (m_nCurrentToken == QL_1_TOK_OPEN_PAREN)
{
trace(("Open Paren: Entering subexpression\n"));
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
if (expr())
return SYNTAX_ERROR;
if (m_nCurrentToken != QL_1_TOK_CLOSE_PAREN)
return SYNTAX_ERROR;
trace(("Close paren: Exiting subexpression\n"));
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
// IDENTIFIER <leading_ident_expr> <finalize>
// ==========================================
else if (m_nCurrentToken == QL_1_TOK_IDENT)
{
trace((" Identifier <%S>\n", m_pTokenText));
if(nRes = parse_property_name(m_PropertyName))
return nRes;
if (nRes = leading_ident_expr())
return SYNTAX_ERROR;
return finalize();
}
// <typed_constant> <rel_operator> <trailing_prop_expr> <finalize>
// ======================================================
else if (m_nCurrentToken == QL_1_TOK_INT ||
m_nCurrentToken == QL_1_TOK_REAL ||
m_nCurrentToken == QL_1_TOK_TRUE ||
m_nCurrentToken == QL_1_TOK_FALSE ||
m_nCurrentToken == QL_1_TOK_NULL ||
m_nCurrentToken == QL_1_TOK_QSTRING
)
{
if (nRes = typed_constant())
return nRes;
if (nRes = rel_operator())
return nRes;
// dont allow const followed by isa!
if(m_nRelOp == QL1_OPERATOR_ISA)
return SYNTAX_ERROR;
// Since we always view the token as IDENT <rel> constant, we need
// to invert this operator, e.g. replace > with <
// ================================================================
m_nRelOp = FlipOperator(m_nRelOp);
if (nRes = trailing_prop_expr())
return nRes;
return finalize();
}
return SYNTAX_ERROR;
}
//***************************************************************************
//
// <trailing_prop_expr> ::= IDENTIFIER
//
//***************************************************************************
// ok
int CAbstractQl1Parser::trailing_prop_expr()
{
if (m_nCurrentToken != QL_1_TOK_IDENT)
return SYNTAX_ERROR;
int nRes = parse_property_name(m_PropertyName);
return nRes;
}
//***************************************************************************
//
// <leading_ident_expr> ::= <comp_operator> <trailing_const_expr>;
// <leading_ident_expr> ::= <equiv_operator> <trailing_or_null>;
// <leading_ident_expr> ::= <is_operator> NULL;
//
//***************************************************************************
// ok
int CAbstractQl1Parser::leading_ident_expr()
{
int nRes;
if (SUCCESS == comp_operator())
{
return trailing_const_expr();
}
else if(SUCCESS == equiv_operator())
return trailing_or_null();
nRes = is_operator();
if(nRes != SUCCESS)
return nRes;
if (m_nCurrentToken != QL_1_TOK_NULL)
return LEXICAL_ERROR;
if (Next())
{
V_VT(&m_vTypedConst) = VT_NULL;
return SUCCESS;
}
else
return LEXICAL_ERROR;
}
//***************************************************************************
//
// <trailing_or_null> ::= NULL;
// <trailing_or_null> ::= <trailing_const_expr>;
//
//***************************************************************************
int CAbstractQl1Parser::trailing_or_null()
{
if (m_nCurrentToken == QL_1_TOK_NULL)
{
if (!Next())
return LEXICAL_ERROR;
else
{
V_VT(&m_vTypedConst) = VT_NULL;
return SUCCESS;
}
}
return trailing_const_expr();
}
//***************************************************************************
//
// <trailing_const_expr> ::= IDENTIFIER OPEN_PAREN
// <typed_constant> CLOSE_PAREN;
// <trailing_const_expr> ::= <typed_constant>;
// <trailing_const_expr> ::= <trailing_ident_expr>
//
//***************************************************************************
// ok
int CAbstractQl1Parser::trailing_const_expr()
{
int nRes;
nRes = typed_constant();
if (nRes != SUCCESS)
nRes = trailing_ident_expr();
return nRes;
}
//***************************************************************************
//
// <trailing_ident_expr> ::= <property_name>
//
//***************************************************************************
// ok
int CAbstractQl1Parser::trailing_ident_expr()
{
int nRes = parse_property_name(m_PropertyName2) ;
if (nRes == SUCCESS)
m_bPropComp = TRUE;
return nRes;
}
//***************************************************************************
//
// <finalize> ::= <>;
//
// This composes the QL_LEVEL_1_TOKEN for a simple relational expression,
// complete with any associated intrinsic functions. All of the other
// parse functions help isolate the terms of the expression, but only
// this function builds the token.
//
// To build the token, the following member variables are used:
// m_pPropName
// m_vTypedConst
// m_dwPropFunction
// m_dwConstFunction
// m_nRelOp;
//
// After the token is built, these are cleared/deallocated as appropriate.
// No tokens are consumed and the input is not advanced.
//
//***************************************************************************
int CAbstractQl1Parser::finalize()
{
// At this point, we have all the info needed for a token.
// =======================================================
WBEM_QL1_TOKEN NewTok;
InitToken(&NewTok);
NewTok.m_lTokenType = QL1_OP_EXPRESSION;
VariantInit(&NewTok.m_vConstValue);
memcpy((void*)&NewTok.m_PropertyName,
(void*)(WBEM_PROPERTY_NAME*)&m_PropertyName,
sizeof(WBEM_PROPERTY_NAME));
if (m_bPropComp)
{
NewTok.m_bPropComp = true;
memcpy((void*)&NewTok.m_PropertyName2,
(void*)(WBEM_PROPERTY_NAME*)&m_PropertyName2,
sizeof(WBEM_PROPERTY_NAME));
}
else
{
NewTok.m_bPropComp = false;
if ( FAILED(VariantCopy(&NewTok.m_vConstValue, &m_vTypedConst) ))
{
return OUT_OF_MEMORY;
}
}
NewTok.m_lOperator = m_nRelOp;
NewTok.m_lPropertyFunction = m_dwPropFunction;
NewTok.m_lConstFunction = m_dwConstFunction;
NewTok.m_bQuoted = m_bQuoted;
AddAppropriateToken(NewTok);
// m_PropertyName.m_lNumElements = 0;
// m_PropertyName.m_aElements = NULL;
m_PropertyName.Empty();
m_PropertyName2.Empty();
// Cleanup.
// ========
VariantClear(&m_vTypedConst);
VariantClear(&NewTok.m_vConstValue);
m_nRelOp = 0;
m_dwPropFunction = 0;
m_dwConstFunction = 0;
m_bPropComp = FALSE;
return SUCCESS;
}
//***************************************************************************
//
// <typed_constant> ::= VARIANT;
//
// Ouput: m_vTypedConst is set to the value of the constant. The only
// supported types are VT_I4, VT_R8 and VT_BSTR.
//
//***************************************************************************
int CAbstractQl1Parser::typed_constant()
{
trace((" Typed constant <%S> ", m_pTokenText));
VariantClear(&m_vTypedConst);
m_bQuoted = FALSE;
if (m_nCurrentToken == QL_1_TOK_INT)
{
trace((" Integer\n"));
// Read it in as a 64-bit one
// ==========================
__int64 i64;
unsigned __int64 ui64;
BOOL b32bits = FALSE;
if(ReadI64(m_pTokenText, i64))
{
// Check if it is within range of I4
// =================================
if(i64 >= - (__int64)0x80000000 && i64 <= 0x7FFFFFFF)
{
V_VT(&m_vTypedConst) = VT_I4;
V_I4(&m_vTypedConst) = (long)i64;
b32bits = TRUE;
}
}
else if(!ReadUI64(m_pTokenText, ui64))
{
// Not a valid number
// ==================
return LEXICAL_ERROR;
}
if(!b32bits)
{
// Valid 64-bit number but not 32-bit
// ==================================
BSTR bstr = SysAllocString(m_pTokenText);
if ( bstr == NULL )
{
return OUT_OF_MEMORY;
}
V_VT(&m_vTypedConst) = VT_BSTR;
V_BSTR(&m_vTypedConst) = bstr;
m_bQuoted = FALSE;
}
}
else if (m_nCurrentToken == QL_1_TOK_QSTRING)
{
trace((" String\n"));
BSTR bstr = SysAllocString(m_pTokenText);
if ( bstr == NULL )
{
return OUT_OF_MEMORY;
}
V_VT(&m_vTypedConst) = VT_BSTR;
V_BSTR(&m_vTypedConst) = bstr;
m_bQuoted = TRUE;
}
else if (m_nCurrentToken == QL_1_TOK_REAL)
{
trace((" Real\n"));
V_VT(&m_vTypedConst) = VT_R8;
bool bSuccess;
V_R8(&m_vTypedConst) = WCHARToDOUBLE(m_pTokenText, bSuccess);
if(bSuccess == false)
return LEXICAL_ERROR;
}
else if(m_nCurrentToken == QL_1_TOK_TRUE)
{
V_VT(&m_vTypedConst) = VT_BOOL;
V_BOOL(&m_vTypedConst) = VARIANT_TRUE;
}
else if(m_nCurrentToken == QL_1_TOK_FALSE)
{
V_VT(&m_vTypedConst) = VT_BOOL;
V_BOOL(&m_vTypedConst) = VARIANT_FALSE;
}
else if (m_nCurrentToken == QL_1_TOK_NULL)
V_VT(&m_vTypedConst) = VT_NULL;
// Else, not a typed constant.
else
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <rel_operator> ::= <equiv_operator>;
// <rel_operator> ::= <comp_operator>;
//
//***************************************************************************
int CAbstractQl1Parser::rel_operator()
{
if(SUCCESS == equiv_operator())
return SUCCESS;
else if (SUCCESS == comp_operator())
return SUCCESS;
else return LEXICAL_ERROR;
}
//***************************************************************************
//
// <equiv_operator> ::= EQUIV_OPERATOR; // =, !=
//
// Output: m_nRelOp is set to the correct operator for a QL_LEVEL_1_TOKEN.
//
//***************************************************************************
int CAbstractQl1Parser::equiv_operator()
{
m_nRelOp = 0;
if (m_nCurrentToken == QL_1_TOK_EQ)
{
trace((" REL OP =\n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUAL;
}
else if (m_nCurrentToken == QL_1_TOK_NE)
{
trace((" REL OP <> (!=) \n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_NOT_EQUAL;
}
else
return SYNTAX_ERROR;
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <is_operator> ::= IS_OPERATOR; // is, isnot
//
// Output: m_nRelOp is set to the correct operator for a QL_LEVEL_1_TOKEN.
//
//***************************************************************************
int CAbstractQl1Parser::is_operator()
{
m_nRelOp = 0;
if (m_nCurrentToken != QL_1_TOK_IS)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken == QL_1_TOK_NOT)
{
m_nRelOp = QL_LEVEL_1_TOKEN::OP_NOT_EQUAL;
if (!Next())
return LEXICAL_ERROR;
trace((" REL OP IS NOT \n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_NOT_EQUAL;
return SUCCESS;
}
else
{
trace((" REL OP IS \n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUAL;
return SUCCESS;
}
return SUCCESS;
}
//***************************************************************************
//
// <comp_operator> ::= COMP_OPERATOR; // <=, >=, <, >, like
//
// Output: m_nRelOp is set to the correct operator for a QL_LEVEL_1_TOKEN.
//
//***************************************************************************
int CAbstractQl1Parser::comp_operator()
{
m_nRelOp = 0;
if (m_nCurrentToken == QL_1_TOK_LE)
{
trace((" REL OP <=\n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN;
}
else if (m_nCurrentToken == QL_1_TOK_LT)
{
trace((" REL OP <\n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_LESSTHAN;
}
else if (m_nCurrentToken == QL_1_TOK_GE)
{
trace((" REL OP >=\n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN;
}
else if (m_nCurrentToken == QL_1_TOK_GT)
{
trace((" REL OP >\n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_GREATERTHAN;
}
else if (m_nCurrentToken == QL_1_TOK_LIKE)
{
trace((" REL OP 'like' \n"));
m_nRelOp = QL_LEVEL_1_TOKEN::OP_LIKE;
}
else if (m_nCurrentToken == QL_1_TOK_ISA)
{
trace((" REL OP 'isa' \n"));
m_nRelOp = QL1_OPERATOR_ISA;
}
else
return SYNTAX_ERROR;
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
return SUCCESS;
}
int CAbstractQl1Parser::opt_aggregation()
{
if(m_nCurrentToken == QL_1_TOK_EOF)
return SUCCESS;
if(m_nCurrentToken != QL_1_TOK_GROUP)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
m_pSink->SetAggregated();
int nRes = aggregation_params();
if(nRes)
return nRes;
if(nRes = opt_having())
return nRes;
// Make sure we've reached the end
// ===============================
if(m_nCurrentToken != QL_1_TOK_EOF)
return SYNTAX_ERROR;
return SUCCESS;
}
int CAbstractQl1Parser::aggregation_params()
{
int nRes;
WBEM_QL1_TOLERANCE Exact;
Exact.m_bExact = TRUE;
if(m_nCurrentToken == QL_1_TOK_BY)
{
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
if(nRes = aggregate_by())
return nRes;
if(m_nCurrentToken == QL_1_TOK_WITHIN)
{
if (!Next())
return LEXICAL_ERROR;
if(nRes = aggregate_within())
return nRes;
}
else
{
m_pSink->SetAggregationTolerance(Exact);
}
}
else if(m_nCurrentToken == QL_1_TOK_WITHIN)
{
if (!Next())
return LEXICAL_ERROR;
if(nRes = aggregate_within())
return nRes;
if(m_nCurrentToken == QL_1_TOK_BY)
{
if (!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
if(nRes = aggregate_by())
return nRes;
}
}
else
{
return SYNTAX_ERROR;
}
return SUCCESS;
}
int CAbstractQl1Parser::aggregate_within()
{
WBEM_QL1_TOLERANCE Tolerance;
Tolerance.m_bExact = FALSE;
LPWSTR wszGarbage;
if (m_nCurrentToken == QL_1_TOK_REAL)
{
bool bSuccess;
Tolerance.m_fTolerance = WCHARToDOUBLE(m_pTokenText, bSuccess);
if(!bSuccess)
return SYNTAX_ERROR;
m_pSink->SetAggregationTolerance(Tolerance);
Next();
return SUCCESS;
}
else if (m_nCurrentToken == QL_1_TOK_INT)
{
Tolerance.m_fTolerance = (double)wcstol(m_pTokenText, &wszGarbage, 10);
m_pSink->SetAggregationTolerance(Tolerance);
Next();
return SUCCESS;
}
else
{
return SYNTAX_ERROR;
}
}
int CAbstractQl1Parser::aggregate_by()
{
m_bInAggregation = TRUE;
int nRes = prop_list();
m_bInAggregation = FALSE;
return nRes;
}
int CAbstractQl1Parser::opt_having()
{
if(m_nCurrentToken == QL_1_TOK_HAVING)
{
if(!Next(EXCLUDE_GROUP_KEYWORD))
return LEXICAL_ERROR;
m_bInAggregation = TRUE;
int nRes = expr();
m_bInAggregation = FALSE;
return nRes;
}
else return SUCCESS;
}
//***************************************************************************
//***************************************************************************
//
// class QL1_Parser
//
// A derivative of CAbstractQlParser for backward compatibility
//
//***************************************************************************
//
//
QL1_Parser::QL1_Parser(CGenLexSource *pSrc)
: m_pExpression(NULL), CAbstractQl1Parser(pSrc), m_bPartiallyParsed(FALSE)
{
m_pExpression = new QL_LEVEL_1_RPN_EXPRESSION;
if ( m_pExpression == NULL )
{
throw CX_MemoryException();
}
}
QL1_Parser::~QL1_Parser()
{
delete m_pExpression;
}
int QL1_Parser::GetQueryClass(
LPWSTR pDestBuf,
int nBufLen
)
{
// Get the underlying parser to parse the first part of the query
// ==============================================================
if(!m_bPartiallyParsed)
{
int nRes = CAbstractQl1Parser::Parse(m_pExpression, NO_WHERE);
if(nRes != SUCCESS) return nRes;
}
if (!m_pExpression->bsClassName)
return SYNTAX_ERROR;
m_bPartiallyParsed = TRUE;
if(wcslen(m_pExpression->bsClassName) >= (unsigned int)nBufLen)
return BUFFER_TOO_SMALL;
wcscpy(pDestBuf, m_pExpression->bsClassName);
return WBEM_S_NO_ERROR;
}
int QL1_Parser::Parse(QL_LEVEL_1_RPN_EXPRESSION **pOutput)
{
*pOutput = NULL;
// Get the underying parser to completely parse the query. If
// GetQueryClass was called in the past, no sense in duplcating
// the work
// ============================================================
QL_LEVEL_1_RPN_EXPRESSION* pTemp = NULL;
try
{
pTemp = new QL_LEVEL_1_RPN_EXPRESSION;
}
catch (CX_MemoryException)
{
return OUT_OF_MEMORY;
}
if ( pTemp == NULL )
{
return OUT_OF_MEMORY;
}
int nRes = CAbstractQl1Parser::Parse(m_pExpression,
m_bPartiallyParsed?JUST_WHERE:FULL_PARSE);
if ( nRes == SUCCESS )
{
*pOutput = m_pExpression;
m_pExpression = pTemp;
m_bPartiallyParsed = FALSE;
}
else
{
delete pTemp;
}
return nRes;
}
DELETE_ME LPWSTR QL1_Parser::ReplaceClassName(QL_LEVEL_1_RPN_EXPRESSION* pExpr,
LPCWSTR wszClassName)
{
QL_LEVEL_1_RPN_EXPRESSION NewExpr(*pExpr);
if (NewExpr.bsClassName)
SysFreeString(NewExpr.bsClassName);
NewExpr.bsClassName = SysAllocString(wszClassName);
if ( NewExpr.bsClassName == NULL )
{
return NULL;
}
LPWSTR wszNewQuery = NewExpr.GetText();
return wszNewQuery;
}
//***************************************************************************
//
// Expression and token structure methods.
//
//***************************************************************************
QL_LEVEL_1_RPN_EXPRESSION::QL_LEVEL_1_RPN_EXPRESSION()
{
nNumTokens = 0;
bsClassName = 0;
bCount = FALSE;
nNumberOfProperties = 0;
bStar = FALSE;
pRequestedPropertyNames = 0;
nCurSize = 1;
nCurPropSize = 1;
pArrayOfTokens = new QL_LEVEL_1_TOKEN[nCurSize];
pRequestedPropertyNames = new CPropertyName[nCurPropSize];
bAggregated = FALSE;
bAggregateAll = FALSE;
nNumAggregatedProperties = 0;
nCurAggPropSize = 1;
pAggregatedPropertyNames = new CPropertyName[nCurAggPropSize];
nNumHavingTokens = 0;
nCurHavingSize = 1;
pArrayOfHavingTokens = new QL_LEVEL_1_TOKEN[nCurHavingSize];
if ( pArrayOfTokens == NULL || pRequestedPropertyNames == NULL ||
pAggregatedPropertyNames == NULL || pArrayOfHavingTokens == NULL )
{
delete [] pArrayOfTokens;
delete [] pRequestedPropertyNames;
delete [] pAggregatedPropertyNames;
delete [] pArrayOfHavingTokens;
throw CX_MemoryException();
}
lRefCount = 0;
}
QL_LEVEL_1_RPN_EXPRESSION::QL_LEVEL_1_RPN_EXPRESSION(
const QL_LEVEL_1_RPN_EXPRESSION& Other)
{
nNumTokens = Other.nNumTokens;
nNumberOfProperties = Other.nNumberOfProperties;
bStar = Other.bStar;
bCount = Other.bCount;
pRequestedPropertyNames = 0;
nCurSize = Other.nCurSize;
nCurPropSize = Other.nCurPropSize;
bAggregated = Other.bAggregated;
bAggregateAll = Other.bAggregateAll;
nNumAggregatedProperties = Other.nNumAggregatedProperties;
nCurAggPropSize = Other.nCurAggPropSize;
nNumHavingTokens = Other.nNumHavingTokens;
nCurHavingSize = Other.nCurHavingSize;
bsClassName = SysAllocString(Other.bsClassName);
pArrayOfTokens = new QL_LEVEL_1_TOKEN[nCurSize];
pRequestedPropertyNames = new CPropertyName[nCurPropSize];
pAggregatedPropertyNames = new CPropertyName[nCurAggPropSize];
pArrayOfHavingTokens = new QL_LEVEL_1_TOKEN[nCurHavingSize];
if ( pArrayOfTokens == NULL || pRequestedPropertyNames == NULL ||
pAggregatedPropertyNames == NULL || pArrayOfHavingTokens == NULL ||
bsClassName == NULL )
{
delete [] pArrayOfTokens;
delete [] pRequestedPropertyNames;
delete [] pAggregatedPropertyNames;
delete [] pArrayOfHavingTokens;
if ( bsClassName != NULL ) SysFreeString( bsClassName );
throw CX_MemoryException();
}
int i;
for(i = 0; i < nNumTokens; i++)
pArrayOfTokens[i] = Other.pArrayOfTokens[i];
for(i = 0; i < nNumberOfProperties; i++)
pRequestedPropertyNames[i] = Other.pRequestedPropertyNames[i];
for(i = 0; i < nNumAggregatedProperties; i++)
pAggregatedPropertyNames[i] = Other.pAggregatedPropertyNames[i];
for(i = 0; i < nNumHavingTokens; i++)
pArrayOfHavingTokens[i] = Other.pArrayOfHavingTokens[i];
lRefCount = 0;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddRef()
{
InterlockedIncrement(&lRefCount);
}
void QL_LEVEL_1_RPN_EXPRESSION::Release()
{
if(InterlockedDecrement(&lRefCount) == 0)
delete this;
}
QL_LEVEL_1_RPN_EXPRESSION::~QL_LEVEL_1_RPN_EXPRESSION()
{
delete [] pArrayOfTokens;
if (bsClassName)
SysFreeString(bsClassName);
delete [] pAggregatedPropertyNames;
delete [] pArrayOfHavingTokens;
delete [] pRequestedPropertyNames;
}
void QL_LEVEL_1_RPN_EXPRESSION::SetClassName(LPCWSTR wszClassName)
{
if ( bsClassName != NULL )
{
SysFreeString( bsClassName );
}
bsClassName = SysAllocString(wszClassName);
if ( bsClassName == NULL )
{
throw CX_MemoryException();
}
}
void QL_LEVEL_1_RPN_EXPRESSION::SetTolerance(
const WBEM_QL1_TOLERANCE& _Tolerance)
{
Tolerance = _Tolerance;
}
void QL_LEVEL_1_RPN_EXPRESSION::SetAggregationTolerance(
const WBEM_QL1_TOLERANCE& _Tolerance)
{
AggregationTolerance = _Tolerance;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddToken(const WBEM_QL1_TOKEN& Tok)
{
if (nCurSize == nNumTokens)
{
nCurSize += 1;
nCurSize *= 2;
QL_LEVEL_1_TOKEN *pTemp = new QL_LEVEL_1_TOKEN[nCurSize];
if ( pTemp == NULL )
{
throw CX_MemoryException();
}
for (int i = 0; i < nNumTokens; i++)
pTemp[i] = pArrayOfTokens[i];
delete [] pArrayOfTokens;
pArrayOfTokens = pTemp;
}
pArrayOfTokens[nNumTokens++] = Tok;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddToken(const QL_LEVEL_1_TOKEN& Tok)
{
if (nCurSize == nNumTokens)
{
nCurSize += 1;
nCurSize *= 2;
QL_LEVEL_1_TOKEN *pTemp = new QL_LEVEL_1_TOKEN[nCurSize];
if ( pTemp == NULL )
{
throw CX_MemoryException();
}
for (int i = 0; i < nNumTokens; i++)
pTemp[i] = pArrayOfTokens[i];
delete [] pArrayOfTokens;
pArrayOfTokens = pTemp;
}
pArrayOfTokens[nNumTokens++] = Tok;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddHavingToken(
const WBEM_QL1_TOKEN& Tok)
{
if (nCurHavingSize == nNumHavingTokens)
{
nCurHavingSize += 1;
nCurHavingSize *= 2;
QL_LEVEL_1_TOKEN *pTemp = new QL_LEVEL_1_TOKEN[nCurHavingSize];
if ( pTemp == NULL )
{
throw CX_MemoryException();
}
for (int i = 0; i < nNumHavingTokens; i++)
pTemp[i] = pArrayOfHavingTokens[i];
delete [] pArrayOfHavingTokens;
pArrayOfHavingTokens = pTemp;
}
pArrayOfHavingTokens[nNumHavingTokens++] = Tok;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddProperty(const CPropertyName& Prop)
{
if (nCurPropSize == nNumberOfProperties)
{
nCurPropSize += 1;
nCurPropSize *= 2;
CPropertyName *pTemp = new CPropertyName[nCurPropSize];
if (!pTemp)
throw CX_MemoryException();
for(int i = 0; i < nNumberOfProperties; i++)
pTemp[i] = pRequestedPropertyNames[i];
delete [] pRequestedPropertyNames;
pRequestedPropertyNames = pTemp;
}
pRequestedPropertyNames[nNumberOfProperties++] = Prop;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddAllProperties()
{
bStar = TRUE;
}
void QL_LEVEL_1_RPN_EXPRESSION::SetCountQuery()
{
bCount = TRUE;
}
void QL_LEVEL_1_RPN_EXPRESSION::SetAggregated()
{
bAggregated = TRUE;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddAggregationProperty(
const CPropertyName& Property)
{
if(pAggregatedPropertyNames == NULL)
{
// '*' requested
return;
}
if (nCurAggPropSize == nNumAggregatedProperties)
{
nCurAggPropSize += 1;
nCurAggPropSize *= 2;
CPropertyName *pTemp = new CPropertyName[nCurAggPropSize];
if ( pTemp == NULL )
{
throw CX_MemoryException();
}
for(int i = 0; i < nNumAggregatedProperties; i++)
pTemp[i] = pAggregatedPropertyNames[i];
delete [] pAggregatedPropertyNames;
pAggregatedPropertyNames = pTemp;
}
pAggregatedPropertyNames[nNumAggregatedProperties++] = Property;
}
void QL_LEVEL_1_RPN_EXPRESSION::AddAllAggregationProperties()
{
bAggregateAll = TRUE;
}
DELETE_ME LPWSTR QL_LEVEL_1_RPN_EXPRESSION::GetText()
{
WString wsText;
wsText += L"select ";
for(int i = 0; i < nNumberOfProperties; i++)
{
if(i != 0) wsText += L", ";
wsText += (LPWSTR)pRequestedPropertyNames[i].GetStringAt(0);
}
if(bStar)
{
if(nNumberOfProperties > 0)
wsText += L", ";
wsText += L"*";
}
wsText += L" from ";
if (bsClassName)
wsText += bsClassName;
if(nNumTokens > 0)
{
wsText += L" where ";
CWStringArray awsStack;
for(int i = 0; i < nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pArrayOfTokens[i];
LPWSTR wszTokenText = Token.GetText();
if(wszTokenText == NULL)
return NULL;
if(Token.nTokenType == QL1_OP_EXPRESSION)
{
awsStack.Add(wszTokenText);
delete [] wszTokenText;
}
else if(Token.nTokenType == QL1_NOT)
{
LPWSTR wszLast = awsStack[awsStack.Size()-1];
WString wsNew;
wsNew += wszTokenText;
delete [] wszTokenText;
wsNew += L" (";
wsNew += wszLast;
wsNew += L")";
awsStack.RemoveAt(awsStack.Size()-1); //pop
awsStack.Add(wsNew);
}
else
{
if(awsStack.Size() < 2) return NULL;
LPWSTR wszLast = awsStack[awsStack.Size()-1];
LPWSTR wszPrev = awsStack[awsStack.Size()-2];
WString wsNew;
wsNew += L"(";
wsNew += wszPrev;
wsNew += L" ";
wsNew += wszTokenText;
delete [] wszTokenText;
wsNew += L" ";
wsNew += wszLast;
wsNew += L")";
awsStack.RemoveAt(awsStack.Size()-1); //pop
awsStack.RemoveAt(awsStack.Size()-1); //pop
awsStack.Add(wsNew);
}
}
if(awsStack.Size() != 1) return NULL;
wsText += awsStack[0];
}
return wsText.UnbindPtr();
}
void QL_LEVEL_1_RPN_EXPRESSION::Dump(const char *pszTextFile)
{
FILE *f = fopen(pszTextFile, "wt");
if (!f)
return;
fprintf(f, "----RPN Expression----\n");
fprintf(f, "Class name = %S\n", bsClassName);
fprintf(f, "Properties selected: ");
if (!nNumberOfProperties)
{
fprintf(f, "* = all properties selected\n");
}
else for (int i = 0; i < nNumberOfProperties; i++)
{
fprintf(f, "%S ", pRequestedPropertyNames[i].GetStringAt(0));
}
fprintf(f, "\n------------------\n");
fprintf(f, "Tokens:\n");
for (int i = 0; i < nNumTokens; i++)
pArrayOfTokens[i].Dump(f);
fprintf(f, "---end of expression---\n");
fclose(f);
}
QL_LEVEL_1_TOKEN::QL_LEVEL_1_TOKEN()
{
nTokenType = 0;
nOperator = 0;
VariantInit(&vConstValue);
dwPropertyFunction = 0;
dwConstFunction = 0;
bQuoted = TRUE;
m_bPropComp = FALSE;
}
QL_LEVEL_1_TOKEN::QL_LEVEL_1_TOKEN(const QL_LEVEL_1_TOKEN &Src)
{
nTokenType = 0;
nOperator = 0;
VariantInit(&vConstValue);
dwPropertyFunction = 0;
dwConstFunction = 0;
bQuoted = TRUE;
m_bPropComp = FALSE;
*this = Src;
}
QL_LEVEL_1_TOKEN& QL_LEVEL_1_TOKEN::operator =(const QL_LEVEL_1_TOKEN &Src)
{
if ( FAILED(VariantCopy(&vConstValue, (VARIANT*)&Src.vConstValue)) )
{
throw CX_MemoryException();
}
nTokenType = Src.nTokenType;
PropertyName = Src.PropertyName;
if (Src.m_bPropComp)
PropertyName2 = Src.PropertyName2;
nOperator = Src.nOperator;
dwPropertyFunction = Src.dwPropertyFunction;
dwConstFunction = Src.dwConstFunction;
bQuoted = Src.bQuoted;
m_bPropComp = Src.m_bPropComp;
return *this;
}
QL_LEVEL_1_TOKEN& QL_LEVEL_1_TOKEN::operator =(const WBEM_QL1_TOKEN &Src)
{
if ( FAILED(VariantCopy(&vConstValue, (VARIANT*)&Src.m_vConstValue) ) )
{
throw CX_MemoryException();
}
nTokenType = Src.m_lTokenType;
PropertyName = Src.m_PropertyName;
if (Src.m_bPropComp)
PropertyName2 = Src.m_PropertyName2;
nOperator = Src.m_lOperator;
dwPropertyFunction = Src.m_lPropertyFunction;
dwConstFunction = Src.m_lConstFunction;
bQuoted = Src.m_bQuoted;
m_bPropComp = Src.m_bPropComp;
return *this;
}
QL_LEVEL_1_TOKEN::~QL_LEVEL_1_TOKEN()
{
nTokenType = 0;
nOperator = 0;
VariantClear(&vConstValue);
}
DELETE_ME LPWSTR QL_LEVEL_1_TOKEN::GetText()
{
WString wsText;
LPWSTR wszPropName;
switch (nTokenType)
{
case OP_EXPRESSION:
wszPropName = PropertyName.GetText();
if(wszPropName == NULL)
return NULL;
wsText += wszPropName;
delete [] wszPropName;
wsText += L" ";
WCHAR* wszOp;
switch (nOperator)
{
case OP_EQUAL: wszOp = L"="; break;
case OP_NOT_EQUAL: wszOp = L"<>"; break;
case OP_EQUALorGREATERTHAN: wszOp = L">="; break;
case OP_EQUALorLESSTHAN: wszOp = L"<="; break;
case OP_LESSTHAN: wszOp = L"<"; break;
case OP_GREATERTHAN: wszOp = L">"; break;
case OP_LIKE: wszOp = L"LIKE"; break;
case QL1_OPERATOR_ISA: wszOp = L"ISA"; break;
default: wszOp = NULL;
}
if(wszOp)
wsText += wszOp;
wsText += L" ";
if (m_bPropComp)
{
// property comparison (e.g., prop1 > prop2)
wszPropName = PropertyName2.GetText();
if(wszPropName == NULL)
return NULL;
wsText += wszPropName;
delete [] wszPropName;
}
else
{
// expression with constant (e.g., prop1 > 5)
WCHAR wszConst[100];
switch (V_VT(&vConstValue))
{
case VT_NULL:
wsText += L"NULL";
break;
case VT_I4:
swprintf(wszConst, L"%d", V_I4(&vConstValue));
wsText += wszConst;
break;
case VT_I2:
swprintf(wszConst, L"%d", (int)V_I2(&vConstValue));
wsText += wszConst;
break;
case VT_UI1:
swprintf(wszConst, L"%d", (int)V_UI1(&vConstValue));
wsText += wszConst;
break;
case VT_BSTR:
{
if(bQuoted)
wsText += L"\"";
//If we need to parse the string we do it the hard way
WCHAR* pwc = V_BSTR(&vConstValue);
BOOL bLongMethod = FALSE;
for (int tmp = 0; pwc[tmp]; tmp++)
if ((pwc[tmp] == L'\\') || (pwc[tmp] == L'"'))
bLongMethod = TRUE;
if (bLongMethod)
{
for(pwc; *pwc; pwc++)
{
if(*pwc == L'\\' || *pwc == L'"')
wsText += L'\\';
wsText += *pwc;
}
}
else
{
//otherwise we do it the fast way...
wsText += pwc;
}
if(bQuoted)
wsText += L"\"";
}
break;
case VT_R4:
swprintf(wszConst, L"%G", V_R4(&vConstValue));
wsText += wszConst;
break;
case VT_R8:
swprintf(wszConst, L"%lG", V_R8(&vConstValue));
wsText += wszConst;
break;
case VT_BOOL:
wsText += (V_BOOL(&vConstValue)?L"TRUE":L"FALSE");
break;
}
}
break;
case TOKEN_AND:
wsText = "AND";
break;
case TOKEN_OR:
wsText = "OR";
break;
case TOKEN_NOT:
wsText = "NOT";
break;
}
return wsText.UnbindPtr();
}
void QL_LEVEL_1_TOKEN::Dump(FILE *f)
{
switch (nTokenType)
{
case OP_EXPRESSION:
fprintf(f, "OP_EXPRESSION ");
break;
case TOKEN_AND:
fprintf(f, "TOKEN_AND ");
break;
case TOKEN_OR:
fprintf(f, "TOKEN_OR ");
break;
case TOKEN_NOT:
fprintf(f, "TOKEN_NOT ");
break;
default:
fprintf(f, "Error: no token type specified\n");
}
if (nTokenType == OP_EXPRESSION)
{
char *pOp = "<no op>";
switch (nOperator)
{
case OP_EQUAL: pOp = "OP_EQUAL"; break;
case OP_NOT_EQUAL: pOp = "OP_NOT_EQUAL"; break;
case OP_EQUALorGREATERTHAN: pOp = "OP_EQUALorGREATERTHAN"; break;
case OP_EQUALorLESSTHAN: pOp = "OP_EQUALorLESSTHAN"; break;
case OP_LESSTHAN: pOp = "OP_LESSTHAN"; break;
case OP_GREATERTHAN: pOp = "OP_GREATERTHAN"; break;
case OP_LIKE: pOp = "OP_LIKE"; break;
}
LPWSTR wszPropName = PropertyName.GetText();
if(wszPropName == NULL)
return;
fprintf(f, " Property = %S\n", wszPropName);
delete [] wszPropName;
fprintf(f, " Operator = %s\n", pOp);
fprintf(f, " Value = ");
if (m_bPropComp)
{
wszPropName = PropertyName2.GetText();
if(wszPropName == NULL)
return;
fprintf(f, " <Property:%S>\n", wszPropName);
delete [] wszPropName;
}
else
{
switch (V_VT(&vConstValue))
{
case VT_I4:
fprintf(f, "VT_I4 = %d\n", V_I4(&vConstValue));
break;
case VT_I2:
fprintf(f, "VT_I2 = %d\n", (int)V_I2(&vConstValue));
break;
case VT_UI1:
fprintf(f, "VT_UI1 = %d\n", (int)V_UI1(&vConstValue));
break;
case VT_BSTR:
fprintf(f, "VT_BSTR = %S\n", V_BSTR(&vConstValue));
break;
case VT_R4:
fprintf(f, "VT_R4 = %f\n", V_R4(&vConstValue));
break;
case VT_R8:
fprintf(f, "VT_R8 = %f\n", V_R8(&vConstValue));
break;
case VT_BOOL:
fprintf(f, "%S\n", V_BOOL(&vConstValue)?L"TRUE":L"FALSE");
break;
case VT_NULL:
fprintf(f, "%S\n", L"NULL");
break;
default:
fprintf(f, "<unknown>\n");
}
switch (dwPropertyFunction)
{
case IFUNC_NONE:
break;
case IFUNC_LOWER:
fprintf(f, "Intrinsic function LOWER() applied to property\n");
break;
case IFUNC_UPPER:
fprintf(f, "Intrinsic function UPPER() applied to property\n");
break;
}
switch (dwConstFunction)
{
case IFUNC_NONE:
break;
case IFUNC_LOWER:
fprintf(f, "Intrinsic function LOWER() applied to const value\n");
break;
case IFUNC_UPPER:
fprintf(f, "Intrinsic function UPPER() applied to const value\n");
break;
}
}
}
fprintf(f, " <end of token>\n");
}
/////////////////////////////////////////////////////////////////////////////
//
// Algorithm for evaluating the expression, assuming that it has been
// tokenized and translated to Reverse Polish.
//
// Starting point: (a) An array of QL tokens.
// (b) An empty boolean token stack.
//
// 1. Read Next Token
//
// 2. If a SIMPLE EXPRESSION, evaluate it to TRUE or FALSE, and
// place this boolean result on the stack. Go to 1.
//
// 3. If an OR operator, then pop a boolean token into A,
// pop another boolean token into B. If either A or B are TRUE,
// stack TRUE. Else stack FALSE.
// Go to 1.
//
// 4. If an AND operator, then pop a boolean token into A,
// and pop another into B. If both are TRUE, stack TRUE.
// Else stack FALSE.
// Go to 1.
//
// 5. If a NOT operator, reverse the value of the top-of-stack boolean.
// Go to 1.
//
// At end-of-input, the result is at top-of-stack.
//
/////////////////////////////////////////////////////////////////////////////