|
|
/*++
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.
//
/////////////////////////////////////////////////////////////////////////////
|