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.

537 lines
13 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. SQL1FILT.CPP
  5. Abstract:
  6. History:
  7. --*/
  8. #include "sql1filt.h"
  9. void* CSql1Filter::GetInterface(REFIID riid)
  10. {
  11. if(riid == IID_IHmmFilter || riid == IID_IHmmSql1Filter)
  12. return (IHmmSql1Filter*)&m_XFilter;
  13. else if(riid == IID_IConfigureHmmSql1Filter)
  14. return (IConfigureHmmSql1Filter*)&m_XConfigure;
  15. else if(riid == IID_IHmmParse)
  16. return (IHmmParse*)&m_XParse;
  17. else
  18. return NULL;
  19. }
  20. STDMETHODIMP CSql1Filter::XFilter::
  21. IsSpecial()
  22. {
  23. if(m_pObject->m_apTokens.GetSize() == 0)
  24. {
  25. return HMM_S_ACCEPTS_EVERYTHING;
  26. }
  27. else
  28. {
  29. return HMM_S_FALSE;
  30. }
  31. }
  32. STDMETHODIMP CSql1Filter::XFilter::
  33. CheckObject(IN IHmmPropertySource* pSource,
  34. OUT IHmmPropertyList** ppList, OUT IUnknown** ppHint)
  35. {
  36. if(ppHint) *ppHint = NULL;
  37. return m_pObject->Evaluate(FALSE, pSource, ppList);
  38. }
  39. STDMETHODIMP CSql1Filter::XFilter::
  40. GetType(IID* piid)
  41. {
  42. if(piid == NULL)
  43. return HMM_E_INVALID_PARAMETER;
  44. *piid = IID_IHmmSql1Filter;
  45. return HMM_S_NO_ERROR;
  46. }
  47. STDMETHODIMP CSql1Filter::XFilter::
  48. GetSelectedPropertyList(IN long lFlags, OUT IHmmPropertyList** ppList)
  49. {
  50. return m_pObject->m_TargetClass.GetSelected().QueryInterface(
  51. IID_IHmmPropertyList,
  52. (void**)ppList);
  53. }
  54. STDMETHODIMP CSql1Filter::XFilter::
  55. GetTargetClass(OUT HMM_CLASS_INFO* pTargetClass)
  56. {
  57. if(pTargetClass == NULL)
  58. return HMM_E_INVALID_PARAMETER;
  59. m_pObject->m_XParse.EnsureTarget();
  60. m_pObject->m_TargetClass.Save(*pTargetClass);
  61. return HMM_S_NO_ERROR;
  62. }
  63. STDMETHODIMP CSql1Filter::XFilter::
  64. GetTokens(IN long lFirstIndex, IN long lNumTokens, OUT long* plTokensReturned,
  65. OUT HMM_SQL1_TOKEN* aTokens)
  66. {
  67. if(plTokensReturned == NULL || lNumTokens <= 0 || lFirstIndex < 0 ||
  68. aTokens == NULL)
  69. {
  70. return HMM_E_INVALID_PARAMETER;
  71. }
  72. m_pObject->m_XParse.EnsureWhere();
  73. long lHaveTokens = m_pObject->m_apTokens.GetSize();
  74. if(lFirstIndex >= lHaveTokens)
  75. {
  76. *plTokensReturned = 0;
  77. return HMM_S_NO_MORE_DATA;
  78. }
  79. long lGaveTokens = 0;
  80. long lCurrentIndex = lFirstIndex;
  81. while(lGaveTokens < lNumTokens && lCurrentIndex < lHaveTokens)
  82. {
  83. CSql1Token* pToken = m_pObject->m_apTokens[lCurrentIndex];
  84. if(pToken->m_lTokenType != TOKENTYPE_SPECIAL)
  85. {
  86. pToken->Save(aTokens[lGaveTokens++]);
  87. }
  88. lCurrentIndex++;
  89. }
  90. *plTokensReturned = lGaveTokens;
  91. return HMM_S_NO_ERROR;
  92. }
  93. //********************************* Configuration ******************************
  94. STDMETHODIMP CSql1Filter::XConfigure::
  95. SetTargetClass(IN HMM_CLASS_INFO* pTargetClass)
  96. {
  97. if(pTargetClass == NULL)
  98. return HMM_E_INVALID_PARAMETER;
  99. m_pObject->m_TargetClass.Load(*pTargetClass);
  100. m_pObject->InvalidateTree();
  101. return HMM_S_NO_ERROR;
  102. }
  103. STDMETHODIMP CSql1Filter::XConfigure::
  104. AddTokens(IN long lNumTokens, IN HMM_SQL1_TOKEN* aTokens)
  105. {
  106. if(lNumTokens <= 0 || aTokens == NULL)
  107. return HMM_E_INVALID_PARAMETER;
  108. for(long l = 0; l < lNumTokens; l++)
  109. {
  110. m_pObject->m_apTokens.Add(new CSql1Token(aTokens[l]));
  111. }
  112. m_pObject->InvalidateTree();
  113. return HMM_S_NO_ERROR;
  114. }
  115. STDMETHODIMP CSql1Filter::XConfigure::
  116. RemoveAllTokens()
  117. {
  118. m_pObject->m_apTokens.RemoveAll();
  119. m_pObject->InvalidateTree();
  120. return HMM_S_NO_ERROR;
  121. }
  122. STDMETHODIMP CSql1Filter::XConfigure::
  123. RemoveAllProperties()
  124. {
  125. return m_pObject->m_TargetClass.GetSelected().RemoveAllProperties();
  126. }
  127. STDMETHODIMP CSql1Filter::XConfigure::
  128. AddProperties(IN long lNumProps, HMM_WSTR* awszProps)
  129. {
  130. return m_pObject->m_TargetClass.GetSelected().
  131. AddProperties(lNumProps, awszProps);
  132. }
  133. //*********************************** Parsing *********************************
  134. STDMETHODIMP CSql1Filter::XParse::
  135. Parse(IN HMM_WSTR wszText, IN long lFlags)
  136. {
  137. delete m_pParser;
  138. m_pParser = NULL;
  139. if((lFlags & HMM_FLAG_LAZY) == 0)
  140. {
  141. m_wsText.Empty();
  142. m_nStatus = not_parsing;
  143. m_pObject->InvalidateTree();
  144. CAbstractSql1Parser Parser(new CTextLexSource(wszText));
  145. int nRes = Parser.Parse(this, CAbstractSql1Parser::FULL_PARSE);
  146. m_InnerStack.Empty();
  147. return ParserError(nRes);
  148. }
  149. else
  150. {
  151. m_wsText = wszText;
  152. m_pParser = new CAbstractSql1Parser(new CTextLexSource((LPWSTR)m_wsText));
  153. m_nStatus = at_0;
  154. return HMM_S_NO_ERROR;
  155. }
  156. }
  157. void CSql1Filter::XParse::SetClassName(LPCWSTR wszClass)
  158. {
  159. m_pObject->m_TargetClass.AccessClassName() = (LPWSTR)wszClass;
  160. m_pObject->m_TargetClass.AccessIncludeChildren() = TRUE;
  161. }
  162. void CSql1Filter::XParse::AddToken(COPY const HMM_SQL1_TOKEN& Token)
  163. {
  164. m_pObject->m_apTokens.Add(new CSql1Token(Token));
  165. if(Token.m_lTokenType == SQL1_OR || Token.m_lTokenType == SQL1_AND)
  166. {
  167. // Find the inner guy
  168. // ==================
  169. long lInnerIndex;
  170. if(!m_InnerStack.Pop(lInnerIndex))
  171. return;
  172. V_I4(&m_pObject->m_apTokens[lInnerIndex]->m_vConstValue) =
  173. m_pObject->m_apTokens.GetSize();
  174. }
  175. }
  176. void CSql1Filter::XParse::AddProperty(COPY LPCWSTR wszProperty)
  177. {
  178. m_pObject->m_TargetClass.GetSelected().
  179. AddProperties(1, (LPWSTR*)&wszProperty);
  180. }
  181. void CSql1Filter::XParse::AddAllProperties()
  182. {
  183. m_pObject->m_TargetClass.GetSelected().AddAllProperties();
  184. }
  185. void CSql1Filter::XParse::InOrder(long lOp)
  186. {
  187. /*
  188. CSql1Token* pToken = new CSql1Token;
  189. pToken->m_lTokenType = TOKENTYPE_SPECIAL;
  190. pToken->m_lOperator = lOp;
  191. V_I4(&pToken->m_vConstValue) = -1;
  192. m_InnerStack.Push(m_pObject->m_apTokens.GetSize());
  193. m_pObject->m_apTokens.Add(pToken);
  194. */
  195. }
  196. HRESULT CSql1Filter::XParse::EnsureTarget()
  197. {
  198. if(m_nStatus == at_0)
  199. {
  200. m_pObject->InvalidateTree();
  201. int nRes = m_pParser->Parse(this, CAbstractSql1Parser::NO_WHERE);
  202. m_nStatus = at_where;
  203. return ParserError(nRes);
  204. }
  205. else return HMM_S_NO_ERROR;
  206. }
  207. HRESULT CSql1Filter::XParse::EnsureWhere()
  208. {
  209. if(m_nStatus == not_parsing)
  210. {
  211. return HMM_S_NO_ERROR;
  212. }
  213. else
  214. {
  215. m_pObject->InvalidateTree();
  216. int nRes = m_pParser->Parse(this,
  217. (m_nStatus == at_0)?CAbstractSql1Parser::FULL_PARSE
  218. :CAbstractSql1Parser::JUST_WHERE);
  219. m_InnerStack.Empty();
  220. delete m_pParser;
  221. m_pParser = NULL;
  222. m_nStatus = not_parsing;
  223. return ParserError(nRes);
  224. }
  225. }
  226. HRESULT CSql1Filter::XParse::ParserError(int nRes)
  227. {
  228. switch(nRes)
  229. {
  230. case CAbstractSql1Parser::SUCCESS:
  231. return HMM_S_NO_ERROR;
  232. case CAbstractSql1Parser::SYNTAX_ERROR:
  233. return HMM_E_INVALID_QUERY;
  234. case CAbstractSql1Parser::LEXICAL_ERROR:
  235. return HMM_E_INVALID_QUERY;
  236. case CAbstractSql1Parser::FAILED:
  237. return HMM_E_FAILED;
  238. default:
  239. return HMM_E_CRITICAL_ERROR;
  240. }
  241. }
  242. CSql1Filter::XParse::~XParse()
  243. {
  244. delete m_pParser;
  245. }
  246. //*****************************************************************************
  247. //*************************** Query Evaluator *********************************
  248. //*****************************************************************************
  249. //*****************************************************************************
  250. //
  251. // See sql1eveal.h for documentation
  252. //
  253. //*****************************************************************************
  254. HRESULT CSql1Filter::Evaluate(BOOL bSkipTarget,
  255. IN READ_ONLY IHmmPropertySource* pPropSource,
  256. OUT IHmmPropertyList** ppList)
  257. {
  258. HRESULT hres;
  259. GetTree();
  260. if(m_pTree) m_pTree->Release();
  261. if(ppList) *ppList = NULL;
  262. hres = CHmmNode::EvaluateNode(m_pTree, pPropSource);
  263. if(hres != HMM_S_NO_ERROR) return hres;
  264. if(ppList)
  265. {
  266. m_TargetClass.GetSelected().QueryInterface(IID_IHmmPropertyList,
  267. (void**)ppList);
  268. }
  269. return HMM_S_NO_ERROR;
  270. if(!bSkipTarget)
  271. {
  272. // Check the class of the object
  273. // =============================
  274. hres = m_XParse.EnsureTarget();
  275. if(FAILED(hres)) return hres;
  276. CHmmClassInfo* pInfo = &m_TargetClass;
  277. hres = CHmmClassInfo::CheckObjectAgainstMany(1, &pInfo,
  278. pPropSource, ppList, NULL);
  279. if(hres != HMM_S_NO_ERROR)
  280. {
  281. // Either an error or a simple class mismatch
  282. // ==========================================
  283. return hres;
  284. }
  285. }
  286. // Now go for the expression
  287. // =========================
  288. hres = m_XParse.EnsureWhere();
  289. if(FAILED(hres)) return hres;
  290. int nNumTokens = m_apTokens.GetSize();
  291. if(nNumTokens == 0)
  292. {
  293. // Empty query
  294. // ===========
  295. return HMM_S_NO_ERROR;
  296. }
  297. // Allocate boolean stack of appropriate length
  298. // ============================================
  299. CBooleanStack Stack(nNumTokens);
  300. for(int nTokenIndex = 0; nTokenIndex < nNumTokens; nTokenIndex++)
  301. {
  302. CSql1Token* pToken = m_apTokens[nTokenIndex];
  303. BOOL bVal1, bVal2;
  304. switch(pToken->m_lTokenType)
  305. {
  306. case SQL1_AND:
  307. // Pop the last two operands and AND them together
  308. // ===============================================
  309. if(!Stack.Pop(bVal1) || !Stack.Pop(bVal2))
  310. {
  311. return HMM_E_INVALID_QUERY;
  312. }
  313. Stack.Push(bVal1 && bVal2);
  314. break;
  315. case SQL1_OR:
  316. // Pop the last two operands and OR them together
  317. // ===============================================
  318. if(!Stack.Pop(bVal1) || !Stack.Pop(bVal2))
  319. {
  320. return HMM_E_INVALID_QUERY;
  321. }
  322. Stack.Push(bVal1 || bVal2);
  323. break;
  324. case SQL1_NOT:
  325. // Pop the last value and invert it
  326. // ================================
  327. if(!Stack.Pop(bVal1))
  328. {
  329. return HMM_E_INVALID_QUERY;
  330. }
  331. Stack.Push(!bVal1);
  332. break;
  333. case SQL1_OP_EXPRESSION:
  334. // Evaluate the expression and push its value
  335. // ==========================================
  336. hres = pToken->Evaluate(pPropSource);
  337. if(FAILED(hres)) return hres;
  338. bVal1 = (hres == HMM_S_NO_ERROR);
  339. Stack.Push(bVal1);
  340. break;
  341. case TOKENTYPE_SPECIAL:
  342. if(!Stack.Pop(bVal1))
  343. {
  344. return HMM_E_INVALID_QUERY;
  345. }
  346. Stack.Push(bVal1);
  347. if((pToken->m_lOperator == SQL1_OR && bVal1) ||
  348. (pToken->m_lOperator == SQL1_AND && !bVal1))
  349. {
  350. nTokenIndex = V_I4(&pToken->m_vConstValue) - 1;
  351. }
  352. break;
  353. }
  354. }
  355. // All tokens have been processed. There better be one element on the stack
  356. // ========================================================================
  357. BOOL bResult;
  358. if(!Stack.Pop(bResult))
  359. {
  360. return HMM_E_INVALID_QUERY;
  361. }
  362. if(!Stack.IsEmpty())
  363. {
  364. return HMM_E_INVALID_QUERY;
  365. }
  366. if(bResult)
  367. return HMM_S_NO_ERROR;
  368. else
  369. return HMM_S_FALSE;
  370. }
  371. CHmmNode* CSql1Filter::GetTree()
  372. {
  373. if(m_pTree != NULL)
  374. {
  375. m_pTree->AddRef();
  376. return m_pTree;
  377. }
  378. // Construct the tree from the RPN
  379. // ===============================
  380. CUniquePointerStack<CHmmNode> aNodes(m_apTokens.GetSize());
  381. CHmmNode* pNode1;
  382. CHmmNode* pNode2;
  383. CLogicalNode* pNewNode;
  384. CSql1Token* pNewToken;
  385. for(int i = 0; i < m_apTokens.GetSize(); i++)
  386. {
  387. CSql1Token* pToken = m_apTokens[i];
  388. switch(pToken->m_lTokenType)
  389. {
  390. case SQL1_OR:
  391. case SQL1_AND:
  392. if(!aNodes.Pop(pNode2)) return NULL;
  393. if(!aNodes.Pop(pNode1)) return NULL;
  394. pNewNode = new CLogicalNode;
  395. pNewNode->m_lTokenType = pToken->m_lTokenType;
  396. pNewNode->Add(pNode1);
  397. pNewNode->Add(pNode2);
  398. aNodes.Push(pNewNode);
  399. break;
  400. case SQL1_NOT:
  401. if(!aNodes.Pop(pNode1)) return NULL;
  402. pNode1->Negate();
  403. aNodes.Push(pNode1);
  404. break;
  405. case SQL1_OP_EXPRESSION:
  406. pNewToken = new CSql1Token(*pToken);
  407. aNodes.Push(pNewToken);
  408. break;
  409. default:
  410. return NULL;
  411. }
  412. }
  413. CHmmNode* pWhere;
  414. if(!aNodes.Pop(pWhere))
  415. {
  416. if(i == 0)
  417. pWhere = NULL;
  418. else
  419. return NULL;
  420. }
  421. if(!aNodes.IsEmpty()) return NULL;
  422. // Add the class check
  423. // ===================
  424. CHmmNode* pTarget = m_TargetClass.GetTree();
  425. CLogicalNode* pMain = new CLogicalNode;
  426. pMain->m_lTokenType = SQL1_AND;
  427. pMain->Add(pTarget);
  428. pTarget->Release(); // Matching GetTree()
  429. if(pWhere)
  430. {
  431. pMain->Add(pWhere);
  432. }
  433. m_pTree = pMain;
  434. m_pTree->AddRef(); // for storage
  435. m_pTree->AddRef(); // for return
  436. m_pTree->Print(stdout, 0);
  437. return m_pTree;
  438. }