Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1488 lines
38 KiB

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
SQL_1.CPP
Abstract:
Level 1 Syntax SQL Parser
Implements the syntax described in SQL_1.BNF. This translates the input
into an RPN stream of tokens.
History:
21-Jun-96 Created.
--*/
#include <ole2.h>
#include <windows.h>
#include <stdio.h>
#include <genlex.h>
#include <sqllex.h>
#include <sql_1.h>
class CX_Exception {};
class CX_MemoryException : CX_Exception {};
//#define trace(x) printf x
#define trace(x)
static DWORD TranslateIntrinsic(LPWSTR pFuncName)
{
if (_wcsicmp(pFuncName, L"UPPER") == 0)
return SQL_LEVEL_1_TOKEN::IFUNC_UPPER;
if (_wcsicmp(pFuncName, L"LOWER") == 0)
return SQL_LEVEL_1_TOKEN::IFUNC_LOWER;
return SQL_LEVEL_1_TOKEN::IFUNC_NONE;
}
SQL1_Parser::SQL1_Parser(CGenLexSource *pSrc)
{
Init(pSrc);
}
SQL1_Parser::~SQL1_Parser()
{
Cleanup();
}
void SQL1_Parser::Init(CGenLexSource *pSrc)
{
m_nLine = 0;
m_pTokenText = 0;
m_nCurrentToken = 0;
m_pExpression = 0;
m_pLexer = 0;
// Semantic transfer variables.
// ============================
m_nRelOp = 0;
VariantInit(&m_vTypedConst);
m_dwPropFunction = 0;
m_dwConstFunction = 0;
m_pIdent = 0;
m_pPropComp = 0;
m_bConstIsStrNumeric = FALSE;
if (pSrc)
{
m_pLexer = new CGenLexer(Sql_1_LexTable, pSrc);
m_pExpression = new SQL_LEVEL_1_RPN_EXPRESSION;
}
}
void SQL1_Parser::Cleanup()
{
VariantClear(&m_vTypedConst);
delete m_pIdent;
delete m_pPropComp;
delete m_pLexer;
delete m_pExpression;
}
void SQL1_Parser::SetSource(CGenLexSource *pSrc)
{
Cleanup();
Init(pSrc);
}
int SQL1_Parser::GetQueryClass(
LPWSTR pDestBuf,
int nBufLen
)
{
if ((!m_pLexer) || (!pDestBuf))
{
return FAILED;
}
// Scan until 'FROM' and then get the class name.
// ==============================================
for (;;)
{
m_nCurrentToken = m_pLexer->NextToken();
if (m_nCurrentToken == SQL_1_TOK_EOF)
{
m_pLexer->Reset();
return FAILED;
}
if (_wcsicmp(m_pLexer->GetTokenText(), L"from") == 0)
{
m_nCurrentToken = m_pLexer->NextToken();
if (m_nCurrentToken != SQL_1_TOK_IDENT)
{
m_pLexer->Reset();
return FAILED;
}
// If here, we have the class name.
// ================================
if (wcslen(m_pLexer->GetTokenText()) >= (size_t)nBufLen)
{
m_pLexer->Reset();
return BUFFER_TOO_SMALL;
}
wcscpy(pDestBuf, m_pLexer->GetTokenText());
break;
}
}
// Reset the scanner.
// ==================
m_pLexer->Reset();
return SUCCESS;
}
int SQL1_Parser::Parse(SQL_LEVEL_1_RPN_EXPRESSION **pOutput)
{
if ((!m_pLexer) || (!pOutput))
{
return FAILED;
}
*pOutput = 0;
int nRes = parse();
if (nRes)
return nRes;
*pOutput = m_pExpression;
m_pExpression = 0;
return SUCCESS;
}
LPSTR ToAnsi(LPWSTR Src)
{
static char buf[256];
WideCharToMultiByte(CP_ACP, NULL, Src, -1, buf, 256, NULL, NULL);
return buf;
}
//***************************************************************************
//
// Next()
//
// Advances to the next token and recognizes keywords, etc.
//
//***************************************************************************
BOOL SQL1_Parser::Next()
{
m_nCurrentToken = m_pLexer->NextToken();
if (m_nCurrentToken == SQL_1_TOK_ERROR)
return FALSE;
m_nLine = m_pLexer->GetLineNum();
m_pTokenText = m_pLexer->GetTokenText();
if (m_nCurrentToken == SQL_1_TOK_EOF)
m_pTokenText = L"<end of file>";
// Keyword check.
// ==============
if (m_nCurrentToken == SQL_1_TOK_IDENT)
{
if (_wcsicmp(m_pTokenText, L"select") == 0)
m_nCurrentToken = SQL_1_TOK_SELECT;
else if (_wcsicmp(m_pTokenText, L"from") == 0)
m_nCurrentToken = SQL_1_TOK_FROM;
else if (_wcsicmp(m_pTokenText, L"where") == 0)
m_nCurrentToken = SQL_1_TOK_WHERE;
else if (_wcsicmp(m_pTokenText, L"like") == 0)
m_nCurrentToken = SQL_1_TOK_LIKE;
else if (_wcsicmp(m_pTokenText, L"or") == 0)
m_nCurrentToken = SQL_1_TOK_OR;
else if (_wcsicmp(m_pTokenText, L"and") == 0)
m_nCurrentToken = SQL_1_TOK_AND;
else if (_wcsicmp(m_pTokenText, L"not") == 0)
m_nCurrentToken = SQL_1_TOK_NOT;
else if (_wcsicmp(m_pTokenText, L"IS") == 0)
m_nCurrentToken = SQL_1_TOK_IS;
else if (_wcsicmp(m_pTokenText, L"NULL") == 0)
m_nCurrentToken = SQL_1_TOK_NULL;
else if (_wcsicmp(m_pTokenText, L"TRUE") == 0)
{
m_nCurrentToken = SQL_1_TOK_BOOL;
m_pTokenText = L"65535";
}
else if (_wcsicmp(m_pTokenText, L"FALSE") == 0)
{
m_nCurrentToken = SQL_1_TOK_BOOL;
m_pTokenText = L"0";
}
}
return TRUE;
}
//***************************************************************************
//
// <parse> ::= SELECT <prop_list> FROM <classname> WHERE <expr>;
//
//***************************************************************************
// ok
int SQL1_Parser::parse()
{
int nRes;
// SELECT
// ======
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken != SQL_1_TOK_SELECT)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
// <prop_list>
// ===========
if (nRes = prop_list())
return nRes;
// FROM
// ====
if (m_nCurrentToken != SQL_1_TOK_FROM)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
// <classname>
// ===========
if (nRes = class_name())
return nRes;
// WHERE clause.
// =============
return opt_where();
}
//***************************************************************************
//
// <opt_where> ::= WHERE <expr>;
// <opt_where> ::= <>;
//
//***************************************************************************
int SQL1_Parser::opt_where()
{
int nRes;
if (m_nCurrentToken == SQL_1_TOK_EOF)
{
trace(("No WHERE clause\n"));
return SUCCESS;
}
if (m_nCurrentToken != SQL_1_TOK_WHERE)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
// <expr>
// ======
if (nRes = expr())
return nRes;
// Verify that the current token is SQL_1_TOK_EOF.
// ===============================================
if (m_nCurrentToken != SQL_1_TOK_EOF)
return SYNTAX_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <prop_list> ::= <property_name> <prop_list_2>;
//
//***************************************************************************
int SQL1_Parser::prop_list()
{
int nRes;
if (m_nCurrentToken != SQL_1_TOK_ASTERISK &&
m_nCurrentToken != SQL_1_TOK_IDENT)
return SYNTAX_ERROR;
if (nRes = property_name())
return nRes;
if (!Next())
return LEXICAL_ERROR;
return prop_list_2();
}
//***************************************************************************
//
// <prop_list_2> ::= COMMA <prop_list>;
// <prop_list_2> ::= <>;
//
//***************************************************************************
int SQL1_Parser::prop_list_2()
{
if (m_nCurrentToken == SQL_1_TOK_COMMA)
{
if (!Next())
return LEXICAL_ERROR;
return prop_list();
}
return SUCCESS;
}
//***************************************************************************
//
// <property_name> ::= PROPERTY_NAME_STRING;
// <property_name> ::= ASTERISK;
//
//***************************************************************************
int SQL1_Parser::property_name()
{
try
{
if (m_nCurrentToken == SQL_1_TOK_ASTERISK)
{
trace(("Asterisk\n"));
// We need to clean up the expression so far.
for (int i = 0; i < m_pExpression->nNumberOfProperties; i++)
SysFreeString(m_pExpression->pbsRequestedPropertyNames[i]);
m_pExpression->nNumberOfProperties = 0;
// This signals 'all properties' to the evaluator
return SUCCESS;
}
// Else a property name.
// =====================
trace(("Property name %S\n", m_pTokenText));
m_pExpression->AddProperty(m_pTokenText);
}
catch (...)
{
return FAILED;
}
return SUCCESS;
}
//***************************************************************************
//
// <classname> ::= CLASS_NAME_STRING;
//
//***************************************************************************
int SQL1_Parser::class_name()
{
if (m_nCurrentToken != SQL_1_TOK_IDENT)
return SYNTAX_ERROR;
trace(("Class name is %S\n", m_pTokenText));
m_pExpression->bsClassName = SysAllocString(m_pTokenText);
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <expr> ::= <term> <expr2>;
//
//***************************************************************************
int SQL1_Parser::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 SQL1_Parser::expr2()
{
int nRes;
while (1)
{
if (m_nCurrentToken == SQL_1_TOK_OR)
{
trace(("Token OR\n"));
if (!Next())
return LEXICAL_ERROR;
if (nRes = term())
return nRes;
SQL_LEVEL_1_TOKEN *pNewTok = new SQL_LEVEL_1_TOKEN;
pNewTok->nTokenType = SQL_LEVEL_1_TOKEN::TOKEN_OR;
m_pExpression->AddToken(pNewTok);
}
else break;
}
return SUCCESS;
}
//***************************************************************************
//
// <term> ::= <simple_expr> <term2>;
//
//***************************************************************************
int SQL1_Parser::term()
{
int nRes;
if (nRes = simple_expr())
return nRes;
if (nRes = term2())
return nRes;
return SUCCESS;
}
//***************************************************************************
//
// <term2> ::= AND <simple_expr> <term2>;
// <term2> ::= <>;
//
//***************************************************************************
int SQL1_Parser::term2()
{
int nRes;
while (1)
{
if (m_nCurrentToken == SQL_1_TOK_AND)
{
trace(("Token AND\n"));
if (!Next())
return LEXICAL_ERROR;
if (nRes = simple_expr())
return nRes;
// Add the AND token.
// ==================
SQL_LEVEL_1_TOKEN *pNewTok = new SQL_LEVEL_1_TOKEN;
pNewTok->nTokenType = SQL_LEVEL_1_TOKEN::TOKEN_AND;
m_pExpression->AddToken(pNewTok);
}
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 SQL1_Parser::simple_expr()
{
int nRes;
// NOT <expr>
// ==========
if (m_nCurrentToken == SQL_1_TOK_NOT)
{
trace(("Operator NOT\n"));
if (!Next())
return LEXICAL_ERROR;
if (nRes = simple_expr())
return nRes;
SQL_LEVEL_1_TOKEN *pNewTok = new SQL_LEVEL_1_TOKEN;
pNewTok->nTokenType = SQL_LEVEL_1_TOKEN::TOKEN_NOT;
m_pExpression->AddToken(pNewTok);
return SUCCESS;
}
// OPEN_PAREN <expr> CLOSE_PAREN
// =============================
else if (m_nCurrentToken == SQL_1_TOK_OPEN_PAREN)
{
trace(("Open Paren: Entering subexpression\n"));
if (!Next())
return LEXICAL_ERROR;
if (expr())
return SYNTAX_ERROR;
if (m_nCurrentToken != SQL_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 == SQL_1_TOK_IDENT)
{
trace((" Identifier <%S>\n", m_pTokenText));
m_pIdent = new wchar_t[wcslen(m_pTokenText) + 1];
if (!m_pIdent)
{
return FAILED;
}
wcscpy(m_pIdent, m_pTokenText);
if (!Next())
return LEXICAL_ERROR;
if (nRes = leading_ident_expr())
return SYNTAX_ERROR;
return finalize();
}
// <typed_constant> <rel_operator> <trailing_prop_expr> <finalize>
// ======================================================
else if (m_nCurrentToken == SQL_1_TOK_INT ||
m_nCurrentToken == SQL_1_TOK_REAL ||
m_nCurrentToken == SQL_1_TOK_QSTRING
)
{
if (nRes = typed_constant())
return nRes;
if (nRes = rel_operator())
return nRes;
if (nRes = trailing_prop_expr())
return nRes;
return finalize();
}
return SYNTAX_ERROR;
}
//***************************************************************************
//
// <trailing_prop_expr> ::= IDENTIFIER <trailing_prop_expr2>;
//
//***************************************************************************
// ok
int SQL1_Parser::trailing_prop_expr()
{
if (m_nCurrentToken != SQL_1_TOK_IDENT)
return SYNTAX_ERROR;
if (!m_pIdent)
{
m_pIdent = new wchar_t[wcslen(m_pTokenText) + 1];
if (!m_pIdent)
{
return FAILED;
}
wcscpy(m_pIdent, m_pTokenText);
}
else
{
m_pPropComp = new wchar_t[wcslen(m_pTokenText) + 1];
if (!m_pPropComp)
{
return FAILED;
}
wcscpy(m_pPropComp, m_pTokenText);
}
if (!Next())
return LEXICAL_ERROR;
return trailing_prop_expr2();
}
//***************************************************************************
//
// <trailing_prop_expr2> ::= OPEN_PAREN IDENTIFIER CLOSE_PAREN;
// <trailing_prop_expr2> ::= <>;
//
//***************************************************************************
// ok
int SQL1_Parser::trailing_prop_expr2()
{
if (m_nCurrentToken == SQL_1_TOK_OPEN_PAREN)
{
if (!Next())
return LEXICAL_ERROR;
// If we got to this point, the string pointed to by m_pIdent
// was an intrinsic function and not a property name, and we
// are about to get the property name, so we have to translate
// the function name to its correct code before overwriting it.
// ============================================================
trace(("Translating intrinsic function %S\n", m_pIdent));
m_dwPropFunction = TranslateIntrinsic(m_pIdent);
delete m_pIdent;
m_pIdent = new wchar_t[wcslen(m_pTokenText) + 1];
if (!m_pIdent)
{
return FAILED;
}
wcscpy(m_pIdent, m_pTokenText);
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken != SQL_1_TOK_CLOSE_PAREN)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
}
trace(("Property name is %S\n", m_pIdent));
return SUCCESS;
}
//***************************************************************************
//
// <leading_ident_expr> ::= OPEN_PAREN <unknown_func_expr>;
// <leading_ident_expr> ::= <comp_operator> <trailing_const_expr>;
// <leading_ident_expr> ::= <equiv_operator> <trailing_or_null>;
// <leading_ident_expr> ::= <is_operator> NULL;
//
//***************************************************************************
// ok
int SQL1_Parser::leading_ident_expr()
{
int nRes;
if (m_nCurrentToken == SQL_1_TOK_OPEN_PAREN)
{
if (!Next())
return LEXICAL_ERROR;
return unknown_func_expr();
}
if (SUCCESS == comp_operator() || SUCCESS == equiv_operator())
return trailing_or_null();
nRes = is_operator();
if(nRes != SUCCESS)
return nRes;
if (m_nCurrentToken != SQL_1_TOK_NULL)
return LEXICAL_ERROR;
if (Next())
{
V_VT(&m_vTypedConst) = VT_NULL;
return SUCCESS;
}
else
return LEXICAL_ERROR;
}
//***************************************************************************
//
// <unknown_func_expr> ::= IDENTIFIER CLOSE_PAREN
// <rel_operator> <trailing_const_expr>;
//
// <unknown_func_expr> ::= <typed_constant> CLOSE_PAREN
// <rel_operator> <trailing_prop_expr>;
//
//***************************************************************************
// ok
int SQL1_Parser::unknown_func_expr()
{
int nRes;
if (m_nCurrentToken == SQL_1_TOK_IDENT)
{
m_dwPropFunction = TranslateIntrinsic(m_pIdent);
delete m_pIdent;
m_pIdent = new wchar_t[wcslen(m_pTokenText) + 1];
if (!m_pIdent)
{
return FAILED;
}
wcscpy(m_pIdent, m_pTokenText);
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken != SQL_1_TOK_CLOSE_PAREN)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
if (nRes = rel_operator())
return nRes;
return trailing_const_expr();
}
// Else the other production.
// ==========================
if (nRes = typed_constant())
return nRes;
// If here, we know that the leading ident was
// an intrinsic function.
// ===========================================
m_dwConstFunction = TranslateIntrinsic(m_pIdent);
delete m_pIdent;
m_pIdent = 0;
if (m_nCurrentToken != SQL_1_TOK_CLOSE_PAREN)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
if (nRes = rel_operator())
return nRes;
return trailing_prop_expr();
}
//***************************************************************************
//
// <trailing_or_null> ::= NULL;
// <trailing_or_null> ::= <trailing_const_expr>;
// <trailing_or_null> ::= <trailing_prop_expr>;
//
//***************************************************************************
int SQL1_Parser::trailing_or_null()
{
int nRes;
if (m_nCurrentToken == SQL_1_TOK_NULL)
{
if (!Next())
return LEXICAL_ERROR;
else
{
V_VT(&m_vTypedConst) = VT_NULL;
return SUCCESS;
}
}
else if (!(nRes = trailing_const_expr()))
return nRes;
return trailing_prop_expr();
}
//***************************************************************************
//
// <trailing_const_expr> ::= IDENTIFIER OPEN_PAREN
// <typed_constant> CLOSE_PAREN;
// <trailing_const_expr> ::= <typed_constant>;
//
//***************************************************************************
// ok
int SQL1_Parser::trailing_const_expr()
{
int nRes;
if (m_nCurrentToken == SQL_1_TOK_IDENT)
{
trace(("Function applied to typed const = %S\n", m_pTokenText));
m_dwConstFunction = TranslateIntrinsic(m_pTokenText);
if (!m_dwConstFunction)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken != SQL_1_TOK_OPEN_PAREN)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
if (nRes = typed_constant())
return nRes;
if (m_nCurrentToken != SQL_1_TOK_CLOSE_PAREN)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
return typed_constant();
}
//***************************************************************************
//
// <finalize> ::= <>;
//
// This composes the SQL_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 SQL1_Parser::finalize()
{
// At this point, we have all the info needed for a token.
// =======================================================
SQL_LEVEL_1_TOKEN *pNewTok = new SQL_LEVEL_1_TOKEN;
if (!pNewTok)
return FAILED;
pNewTok->nTokenType = SQL_LEVEL_1_TOKEN::OP_EXPRESSION;
pNewTok->pPropertyName = SysAllocString(m_pIdent);
if (m_pPropComp)
pNewTok->pPropName2 = SysAllocString(m_pPropComp);
pNewTok->nOperator = m_nRelOp;
VariantInit(&pNewTok->vConstValue);
VariantCopy(&pNewTok->vConstValue, &m_vTypedConst);
pNewTok->dwPropertyFunction = m_dwPropFunction;
pNewTok->dwConstFunction = m_dwConstFunction;
pNewTok->bConstIsStrNumeric = m_bConstIsStrNumeric;
m_pExpression->AddToken(pNewTok);
// Cleanup.
// ========
VariantClear(&m_vTypedConst);
delete m_pIdent;
m_pIdent = 0;
m_nRelOp = 0;
m_dwPropFunction = 0;
m_dwConstFunction = 0;
m_bConstIsStrNumeric = 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 SQL1_Parser::typed_constant()
{
trace((" Typed constant <%S> ", m_pTokenText));
VariantClear(&m_vTypedConst);
m_bConstIsStrNumeric = FALSE;
if (m_nCurrentToken == SQL_1_TOK_INT)
{
trace((" Integer\n"));
DWORD x = wcslen(m_pTokenText);
if (*m_pTokenText == L'-')
{
//negative
if ((x < 11) ||
((x == 11) && (wcscmp(m_pTokenText, L"-2147483648") <= 0)))
{
V_VT(&m_vTypedConst) = VT_I4;
V_I4(&m_vTypedConst) = _wtol(m_pTokenText);
}
else
{
trace((" Actually Integer String\n"));
V_VT(&m_vTypedConst) = VT_BSTR;
V_BSTR(&m_vTypedConst) = SysAllocString(m_pTokenText);
m_bConstIsStrNumeric = TRUE;
}
}
else
{
//positive
if ((x < 10) ||
((x == 10) && (wcscmp(m_pTokenText, L"2147483647") <= 0)))
{
V_VT(&m_vTypedConst) = VT_I4;
V_I4(&m_vTypedConst) = _wtol(m_pTokenText);
}
else
{
trace((" Actually Integer String\n"));
V_VT(&m_vTypedConst) = VT_BSTR;
V_BSTR(&m_vTypedConst) = SysAllocString(m_pTokenText);
m_bConstIsStrNumeric = TRUE;
}
}
}
else if (m_nCurrentToken == SQL_1_TOK_QSTRING)
{
trace((" String\n"));
V_VT(&m_vTypedConst) = VT_BSTR;
V_BSTR(&m_vTypedConst) = SysAllocString(m_pTokenText);
}
else if (m_nCurrentToken == SQL_1_TOK_REAL)
{
trace((" Real\n"));
V_VT(&m_vTypedConst) = VT_R8;
V_R8(&m_vTypedConst) = 0.0;
if (m_pTokenText)
{
VARIANT varFrom;
varFrom.vt = VT_BSTR;
varFrom.bstrVal = SysAllocString(m_pTokenText);
if(varFrom.bstrVal != NULL)
{
VariantClear(&m_vTypedConst);
VariantInit(&m_vTypedConst);
SCODE sc = VariantChangeTypeEx(&m_vTypedConst, &varFrom, 0, 0x409, VT_R8);
VariantClear(&varFrom);
if(sc != S_OK)
{
VariantClear(&m_vTypedConst);
VariantInit(&m_vTypedConst);
return LEXICAL_ERROR;
}
}
}
}
else if (m_nCurrentToken == SQL_1_TOK_BOOL)
{
trace((" Bool\n"));
V_VT(&m_vTypedConst) = VT_BOOL;
if (m_pTokenText && _wcsicmp(m_pTokenText, L"65535") == 0)
{
V_BOOL(&m_vTypedConst) = VARIANT_TRUE;
}
else
V_BOOL(&m_vTypedConst) = VARIANT_FALSE;
}
// 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 SQL1_Parser::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 SQL_LEVEL_1_TOKEN.
//
//***************************************************************************
int SQL1_Parser::equiv_operator()
{
m_nRelOp = 0;
if (m_nCurrentToken == SQL_1_TOK_EQ)
{
trace((" REL OP =\n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_EQUAL;
}
else if (m_nCurrentToken == SQL_1_TOK_NE)
{
trace((" REL OP <> (!=) \n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL;
}
else
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// <is_operator> ::= IS_OPERATOR; // is, isnot
//
// Output: m_nRelOp is set to the correct operator for a SQL_LEVEL_1_TOKEN.
//
//***************************************************************************
int SQL1_Parser::is_operator()
{
m_nRelOp = 0;
if (m_nCurrentToken != SQL_1_TOK_IS)
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
if (m_nCurrentToken == SQL_1_TOK_NOT)
{
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL;
if (!Next())
return LEXICAL_ERROR;
trace((" REL OP IS NOT \n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL;
return SUCCESS;
}
else
{
trace((" REL OP IS \n"));
m_nRelOp = SQL_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 SQL_LEVEL_1_TOKEN.
//
//***************************************************************************
int SQL1_Parser::comp_operator()
{
m_nRelOp = 0;
if (m_nCurrentToken == SQL_1_TOK_LE)
{
trace((" REL OP <=\n"));
if (m_pIdent)
{
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN;
}
else
{
trace((" REL OP changed to >=\n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN;
}
}
else if (m_nCurrentToken == SQL_1_TOK_LT)
{
trace((" REL OP <\n"));
if (m_pIdent)
{
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_LESSTHAN;
}
else
{
trace((" REL OP changed to >\n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_GREATERTHAN;
}
}
else if (m_nCurrentToken == SQL_1_TOK_GE)
{
trace((" REL OP >=\n"));
if (m_pIdent)
{
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN;
}
else
{
trace((" REL OP changed to <=\n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN;
}
}
else if (m_nCurrentToken == SQL_1_TOK_GT)
{
trace((" REL OP >\n"));
if (m_pIdent)
{
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_GREATERTHAN;
}
else
{
trace((" REL OP changed to <\n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_LESSTHAN;
}
}
else if (m_nCurrentToken == SQL_1_TOK_LIKE)
{
trace((" REL OP 'like' \n"));
m_nRelOp = SQL_LEVEL_1_TOKEN::OP_LIKE;
}
else
return SYNTAX_ERROR;
if (!Next())
return LEXICAL_ERROR;
return SUCCESS;
}
//***************************************************************************
//
// Expression and token structure methods.
//
//***************************************************************************
SQL_LEVEL_1_RPN_EXPRESSION::SQL_LEVEL_1_RPN_EXPRESSION()
{
nNumTokens = 0;
pArrayOfTokens = 0;
bsClassName = 0;
nNumberOfProperties = 0;
pbsRequestedPropertyNames = 0;
nCurSize = 32;
nCurPropSize = 32;
pArrayOfTokens = new SQL_LEVEL_1_TOKEN[nCurSize];
pbsRequestedPropertyNames = new BSTR[nCurPropSize];
}
SQL_LEVEL_1_RPN_EXPRESSION::~SQL_LEVEL_1_RPN_EXPRESSION()
{
delete [] pArrayOfTokens;
if (bsClassName)
SysFreeString(bsClassName);
for (int i = 0; i < nNumberOfProperties; i++)
SysFreeString(pbsRequestedPropertyNames[i]);
delete pbsRequestedPropertyNames;
}
void SQL_LEVEL_1_RPN_EXPRESSION::AddToken(SQL_LEVEL_1_TOKEN *pTok)
{
AddToken(*pTok);
delete pTok;
pTok = NULL;
}
void SQL_LEVEL_1_RPN_EXPRESSION::AddToken(SQL_LEVEL_1_TOKEN &pTok)
{
if (nCurSize == nNumTokens)
{
nCurSize += 32;
SQL_LEVEL_1_TOKEN *pTemp = new SQL_LEVEL_1_TOKEN[nCurSize];
if (pTemp)
{
for (int i = 0; i < nNumTokens; i++)
pTemp[i] = pArrayOfTokens[i];
delete [] pArrayOfTokens;
pArrayOfTokens = pTemp;
}
}
if (pArrayOfTokens)
{
pArrayOfTokens[nNumTokens++] = pTok;
}
}
void SQL_LEVEL_1_RPN_EXPRESSION::AddProperty (LPWSTR pProp)
{
if (nCurPropSize == nNumberOfProperties)
{
nCurPropSize += 32;
BSTR *pTemp = new BSTR[nCurPropSize];
if (!pTemp)
throw CX_MemoryException();
if (pbsRequestedPropertyNames)
memcpy(pTemp, pbsRequestedPropertyNames,
sizeof(BSTR) * nNumberOfProperties);
else
{
delete [] pTemp;
throw CX_MemoryException();
}
delete pbsRequestedPropertyNames;
pbsRequestedPropertyNames = pTemp;
}
pbsRequestedPropertyNames[nNumberOfProperties++] = SysAllocString(pProp);
}
void SQL_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 ", pbsRequestedPropertyNames[i]);
}
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);
}
SQL_LEVEL_1_TOKEN::SQL_LEVEL_1_TOKEN()
{
nTokenType = 0;
pPropertyName = 0;
pPropName2 = 0;
nOperator = 0;
VariantInit(&vConstValue);
dwPropertyFunction = 0;
dwConstFunction = 0;
bConstIsStrNumeric = FALSE;
}
SQL_LEVEL_1_TOKEN::SQL_LEVEL_1_TOKEN(SQL_LEVEL_1_TOKEN &Src)
{
nTokenType = 0;
pPropertyName = 0;
pPropName2 = 0;
nOperator = 0;
VariantInit(&vConstValue);
dwPropertyFunction = 0;
dwConstFunction = 0;
bConstIsStrNumeric = FALSE;
*this = Src;
}
SQL_LEVEL_1_TOKEN& SQL_LEVEL_1_TOKEN::operator =(SQL_LEVEL_1_TOKEN &Src)
{
//first clear any old values...
if (pPropertyName)
SysFreeString(pPropertyName);
if (pPropName2)
SysFreeString(pPropName2);
VariantClear(&vConstValue);
nTokenType = Src.nTokenType;
pPropertyName = SysAllocString(Src.pPropertyName);
if (Src.pPropName2)
pPropName2 = SysAllocString(Src.pPropName2);
nOperator = Src.nOperator;
VariantCopy(&vConstValue, &Src.vConstValue);
dwPropertyFunction = Src.dwPropertyFunction;
dwConstFunction = Src.dwConstFunction;
bConstIsStrNumeric = Src.bConstIsStrNumeric;
return *this;
}
SQL_LEVEL_1_TOKEN::~SQL_LEVEL_1_TOKEN()
{
nTokenType = 0;
if (pPropertyName)
SysFreeString(pPropertyName);
if (pPropName2)
SysFreeString(pPropName2);
nOperator = 0;
VariantClear(&vConstValue);
}
void SQL_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;
}
fprintf(f, " Property = %S\n", pPropertyName);
fprintf(f, " Operator = %s\n", pOp);
fprintf(f, " Value = ");
if (pPropName2)
fprintf(f, " <Property:%S\n", pPropName2);
else
{
switch (V_VT(&vConstValue))
{
case VT_I4:
fprintf(f, "VT_I4 = %d\n", V_I4(&vConstValue));
break;
case VT_BSTR:
fprintf(f, "VT_BSTR = %S\n", V_BSTR(&vConstValue));
break;
case VT_R8:
fprintf(f, "VT_R8 = %f\n", V_R8(&vConstValue));
break;
case VT_BOOL:
fprintf(f, "VT_BOOL = %d (%s)\n",
V_BOOL(&vConstValue),
V_BOOL(&vConstValue) == VARIANT_TRUE ? "VARIANT_TRUE" : "VARIANT_FALSE"
);
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 SQL 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.
//
/////////////////////////////////////////////////////////////////////////////