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.

4799 lines
152 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. QENGINE.CPP
  5. Abstract:
  6. WinMgmt Query Engine
  7. History:
  8. raymcc 20-Dec-96 Created
  9. levn 97-98-99 Modified beyond comprehension
  10. raymcc 14-Aug-99 Ripped out and relocated assocs to happy new home
  11. raymcc 22-Apr-00 First mutations for new ProvSS
  12. --*/
  13. #include "precomp.h"
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <wbemcore.h>
  17. #include <wbemstr.h>
  18. #include <wbemmeta.h>
  19. #include <analyser.h>
  20. #include <genutils.h>
  21. #include <DateTimeParser.h>
  22. #include "stack.h"
  23. #include <like.h>
  24. #include "wmimerger.h"
  25. #include <autoptr.h>
  26. #include <wmiarbitrator.h>
  27. //***************************************************************************
  28. //
  29. // Local defs
  30. //
  31. //***************************************************************************
  32. #define INVALID 0x3
  33. //***************************************************************************
  34. //
  35. //***************************************************************************
  36. CQlFilteringSink::CQlFilteringSink(
  37. CBasicObjectSink* pDest,
  38. ADDREF QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  39. CWbemNamespace *pNamespace, BOOL bFilterNow
  40. )
  41. : CFilteringSink(pDest), m_pExpr(pExpr), m_bFilterNow(bFilterNow),
  42. m_pNs(pNamespace)
  43. {
  44. // TBD: consider the query
  45. m_pExpr->AddRef();
  46. }
  47. //***************************************************************************
  48. //
  49. //***************************************************************************
  50. CQlFilteringSink::~CQlFilteringSink()
  51. {
  52. m_pExpr->Release();
  53. }
  54. //***************************************************************************
  55. //
  56. //***************************************************************************
  57. STDMETHODIMP CQlFilteringSink::Indicate(
  58. long lObjectCount,
  59. IWbemClassObject** pObjArray
  60. )
  61. {
  62. if(!m_bFilterNow)
  63. return m_pDest->Indicate(lObjectCount, pObjArray);
  64. return CFilteringSink::Indicate(lObjectCount, pObjArray);
  65. }
  66. BOOL CQlFilteringSink::Test(CWbemObject* pObj)
  67. {
  68. return CQlFilteringSink::Test(pObj, m_pExpr, m_pNs); // this function throws
  69. }
  70. //***************************************************************************
  71. //
  72. //***************************************************************************
  73. BOOL CQlFilteringSink::Test(
  74. CWbemObject* pObj,
  75. QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  76. CWbemNamespace * pNs
  77. )
  78. {
  79. CStack Stack;
  80. // If a pure 'select' with no 'where' clause, we always
  81. // return TRUE.
  82. // ====================================================
  83. if (pExpr->nNumTokens == 0)
  84. return TRUE;
  85. for (int i = 0; i < pExpr->nNumTokens; i++)
  86. {
  87. QL_LEVEL_1_TOKEN& Tok = pExpr->pArrayOfTokens[i];
  88. if (Tok.nTokenType == QL_LEVEL_1_TOKEN::TOKEN_AND)
  89. {
  90. BOOL b1 = (BOOL) Stack.Pop();
  91. BOOL b2 = (BOOL) Stack.Pop();
  92. if (b1 == TRUE && b2 == TRUE)
  93. Stack.Push(TRUE);
  94. else if (b1 == INVALID || b2 == INVALID)
  95. Stack.Push(INVALID);
  96. else
  97. Stack.Push(FALSE);
  98. }
  99. else if (Tok.nTokenType == QL_LEVEL_1_TOKEN::TOKEN_OR)
  100. {
  101. BOOL b1 = (BOOL) Stack.Pop();
  102. BOOL b2 = (BOOL) Stack.Pop();
  103. if (b1 == TRUE || b2 == TRUE)
  104. Stack.Push(TRUE);
  105. else if (b1 == INVALID || b2 == INVALID)
  106. Stack.Push(INVALID);
  107. else
  108. Stack.Push(FALSE);
  109. }
  110. else if (Tok.nTokenType == QL_LEVEL_1_TOKEN::TOKEN_NOT)
  111. {
  112. BOOL b1 = (BOOL) Stack.Pop();
  113. if (b1 == TRUE)
  114. Stack.Push(FALSE);
  115. else if (b1 == INVALID)
  116. Stack.Push(INVALID);
  117. else
  118. Stack.Push(TRUE);
  119. }
  120. else if (Tok.nTokenType == QL_LEVEL_1_TOKEN::OP_EXPRESSION)
  121. {
  122. Stack.Push(EvaluateToken(pObj, Tok, pNs));
  123. }
  124. }
  125. // Pop top element, which becomes the return value.
  126. // ================================================
  127. int nRes = Stack.Pop();
  128. if (nRes == INVALID)
  129. return FALSE;
  130. return (BOOL) nRes;
  131. }
  132. //***************************************************************************
  133. //
  134. //***************************************************************************
  135. int CQlFilteringSink::EvaluateToken(
  136. IWbemPropertySource *pTestObj,
  137. QL_LEVEL_1_TOKEN& Tok,
  138. CWbemNamespace * pNs
  139. )
  140. {
  141. _variant_t PropVal, CompVal;
  142. WBEM_WSTR wszCimType, wszCimType2;
  143. HRESULT hRes;
  144. // Special-case 'this'
  145. // ===================
  146. if(Tok.PropertyName.GetNumElements() == 1 &&
  147. !wbem_wcsicmp(Tok.PropertyName.GetStringAt(0), L"__THIS"))
  148. {
  149. wszCimType = WbemStringCopy(L"object");
  150. V_VT(&PropVal) = VT_UNKNOWN;
  151. hRes = pTestObj->QueryInterface(IID_IWbemClassObject,
  152. (void**)&V_UNKNOWN(&PropVal));
  153. }
  154. else
  155. {
  156. hRes = pTestObj->GetPropertyValue(&Tok.PropertyName, 0,
  157. &wszCimType, &PropVal);
  158. }
  159. if (FAILED(hRes)) return FALSE;
  160. OnDelete<WBEM_WSTR,void(*)(WBEM_WSTR),WbemStringFree> wsf(wszCimType);
  161. // Handle a property-to-property comparison,
  162. if (Tok.m_bPropComp != FALSE)
  163. {
  164. hRes = pTestObj->GetPropertyValue(&Tok.PropertyName2, 0,
  165. &wszCimType2, &CompVal);
  166. if (FAILED(hRes))
  167. return FALSE;
  168. }
  169. else
  170. {
  171. if ( FAILED (VariantCopy(&CompVal, &Tok.vConstValue)) )
  172. return FALSE;
  173. }
  174. // Handle NULLs
  175. // ============
  176. if(V_VT(&PropVal) == VT_NULL)
  177. {
  178. if(V_VT(&CompVal) == VT_NULL)
  179. {
  180. if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL)
  181. return TRUE;
  182. else if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
  183. return FALSE;
  184. else
  185. return INVALID;
  186. }
  187. else
  188. {
  189. if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL)
  190. return FALSE;
  191. else if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
  192. return TRUE;
  193. else
  194. return INVALID;
  195. }
  196. }
  197. else if(V_VT(&CompVal) == VT_NULL)
  198. {
  199. if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL)
  200. return FALSE;
  201. else if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
  202. return TRUE;
  203. else
  204. return INVALID;
  205. }
  206. // Handle references
  207. // =================
  208. if(wszCimType &&
  209. wbem_wcsnicmp(wszCimType, L"ref", 3) == 0 &&
  210. (wszCimType[3] == 0 || wszCimType[3] == L':'))
  211. {
  212. // This is a reference. The only operators allowed are = and !=
  213. // ============================================================
  214. if(PropVal.vt != VT_BSTR || PropVal.bstrVal == NULL)
  215. return INVALID;
  216. if(CompVal.vt != VT_BSTR || CompVal.bstrVal == NULL)
  217. return INVALID;
  218. WCHAR * va = CQueryEngine::NormalizePath(V_BSTR(&PropVal), pNs);
  219. CVectorDeleteMe<WCHAR> del_va(va);
  220. WCHAR * vb = CQueryEngine::NormalizePath(V_BSTR(&CompVal), pNs);
  221. CVectorDeleteMe<WCHAR> del_vb(vb);
  222. if(va == NULL || vb == NULL)
  223. {
  224. ERRORTRACE((LOG_WBEMCORE, "Invalid path %S or %S specified in an association\n", V_BSTR(&PropVal), V_BSTR(&CompVal)));
  225. return INVALID;
  226. }
  227. int nRet;
  228. switch (Tok.nOperator)
  229. {
  230. case QL_LEVEL_1_TOKEN::OP_EQUAL:
  231. nRet = (wbem_wcsicmp(va,vb) == 0);
  232. break;
  233. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
  234. nRet = (wbem_wcsicmp(va, vb) != 0);
  235. break;
  236. default:
  237. nRet = INVALID;
  238. break;
  239. }
  240. return nRet;
  241. }
  242. // Check if ISA is used
  243. // ====================
  244. if(Tok.nOperator == QL1_OPERATOR_ISA ||
  245. Tok.nOperator == QL1_OPERATOR_ISNOTA ||
  246. Tok.nOperator == QL1_OPERATOR_INV_ISA ||
  247. Tok.nOperator == QL1_OPERATOR_INV_ISNOTA)
  248. {
  249. // Account for inversion
  250. // =====================
  251. VARIANT* pv1;
  252. VARIANT* pv2;
  253. int bNeedDerived;
  254. if(Tok.nOperator == QL1_OPERATOR_ISA ||
  255. Tok.nOperator == QL1_OPERATOR_ISNOTA)
  256. {
  257. pv2 = &CompVal;
  258. pv1 = &PropVal;
  259. bNeedDerived = (Tok.nOperator == QL1_OPERATOR_ISA);
  260. }
  261. else
  262. {
  263. pv1 = &CompVal;
  264. pv2 = &PropVal;
  265. bNeedDerived = (Tok.nOperator == QL1_OPERATOR_INV_ISA);
  266. }
  267. // The second argument has to be a string
  268. // ======================================
  269. if(V_VT(pv2) != VT_BSTR)
  270. {
  271. return INVALID;
  272. }
  273. BSTR strParentClass = V_BSTR(pv2);
  274. // The first argument has to be an object or a string
  275. // ==================================================
  276. BOOL bDerived;
  277. if(V_VT(pv1) == VT_EMBEDDED_OBJECT)
  278. {
  279. IWbemClassObject* pObj = (IWbemClassObject*)V_EMBEDDED_OBJECT(pv1);
  280. bDerived = (pObj->InheritsFrom(strParentClass) == WBEM_S_NO_ERROR);
  281. }
  282. else if(V_VT(pv1) == VT_BSTR)
  283. {
  284. // TBD
  285. // ===
  286. return INVALID;
  287. }
  288. else
  289. {
  290. return INVALID;
  291. }
  292. // Now that we have bDerived, see if it matches the requirement
  293. // ============================================================
  294. if(bDerived == bNeedDerived)
  295. return TRUE;
  296. else
  297. return FALSE;
  298. }
  299. // Perform UINT32 workaround
  300. // =========================
  301. if(wszCimType && !wbem_wcsicmp(wszCimType, L"uint32") &&
  302. V_VT(&PropVal) == VT_I4)
  303. {
  304. DWORD dwVal = (DWORD)V_I4(&PropVal);
  305. WCHAR wszVal[20];
  306. StringCchPrintfW(wszVal, 20, L"%lu", dwVal);
  307. BSTR bstrTmp = SysAllocString(wszVal);
  308. if (bstrTmp)
  309. {
  310. V_VT(&PropVal) = VT_BSTR;
  311. V_BSTR(&PropVal) = bstrTmp;
  312. }
  313. else
  314. {
  315. V_VT(&PropVal) = VT_NULL;
  316. }
  317. }
  318. if(wszCimType &&
  319. (!wbem_wcsicmp(wszCimType, L"sint64") ||
  320. !wbem_wcsicmp(wszCimType, L"uint64") ||
  321. !wbem_wcsicmp(wszCimType, L"uint32")) &&
  322. V_VT(&CompVal) != VT_NULL && V_VT(&PropVal) != VT_NULL)
  323. {
  324. BOOL bUnsigned = (wbem_wcsicmp(wszCimType, L"uint64") == 0);
  325. // We have a 64-bit comparison where both sides are present.
  326. // =========================================================
  327. hRes = VariantChangeType(&CompVal, &CompVal, 0,
  328. VT_BSTR);
  329. if(FAILED(hRes))
  330. {
  331. return INVALID;
  332. }
  333. if(bUnsigned)
  334. {
  335. unsigned __int64 ui64Prop, ui64Const;
  336. if(!ReadUI64(V_BSTR(&PropVal), ui64Prop))
  337. return INVALID;
  338. if(!ReadUI64(V_BSTR(&CompVal), ui64Const))
  339. return INVALID;
  340. switch (Tok.nOperator)
  341. {
  342. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (ui64Prop == ui64Const);
  343. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
  344. return (ui64Prop != ui64Const);
  345. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
  346. return (ui64Prop >= ui64Const);
  347. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
  348. return (ui64Prop <= ui64Const);
  349. case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
  350. return (ui64Prop < ui64Const);
  351. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
  352. return (ui64Prop > ui64Const);
  353. case QL_LEVEL_1_TOKEN::OP_LIKE: return (ui64Prop == ui64Const);
  354. }
  355. return INVALID;
  356. }
  357. else
  358. {
  359. __int64 i64Prop, i64Const;
  360. if(!ReadI64(V_BSTR(&PropVal), i64Prop))
  361. return INVALID;
  362. if(!ReadI64(V_BSTR(&CompVal), i64Const))
  363. return INVALID;
  364. switch (Tok.nOperator)
  365. {
  366. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (i64Prop == i64Const);
  367. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
  368. return (i64Prop != i64Const);
  369. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
  370. return (i64Prop >= i64Const);
  371. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
  372. return (i64Prop <= i64Const);
  373. case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
  374. return (i64Prop < i64Const);
  375. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
  376. return (i64Prop > i64Const);
  377. case QL_LEVEL_1_TOKEN::OP_LIKE: return (i64Prop == i64Const);
  378. }
  379. return INVALID;
  380. }
  381. }
  382. if(wszCimType && !wbem_wcsicmp(wszCimType, L"char16") &&
  383. V_VT(&CompVal) == VT_BSTR && V_VT(&PropVal) != VT_NULL)
  384. {
  385. // Coerce strings correctly
  386. // ========================
  387. BSTR str = V_BSTR(&Tok.vConstValue);
  388. if (wcslen(str) != 1) // SEC:REVIEWED 2002-03-22 : OK, provably recognized by lexer
  389. return INVALID;
  390. short va = V_I2(&PropVal);
  391. short vb = str[0];
  392. switch (Tok.nOperator)
  393. {
  394. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  395. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  396. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
  397. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
  398. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
  399. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
  400. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  401. }
  402. return INVALID;
  403. }
  404. if(wszCimType &&
  405. (!wbem_wcsicmp(wszCimType, L"datetime")) &&
  406. V_VT(&CompVal) == VT_BSTR && V_VT(&PropVal) == VT_BSTR)
  407. {
  408. // Parse the constant specified in the query according to the
  409. // SQL rules
  410. // ==========================================================
  411. TCHAR *tszBuffer;
  412. tszBuffer = V_BSTR(&CompVal);
  413. CDateTimeParser dtConst(tszBuffer);
  414. if(!dtConst.IsValidDateTime())
  415. return INVALID;
  416. WCHAR wszConstValDMTF[26];
  417. dtConst.FillDMTF(wszConstValDMTF, 26);
  418. // Read both DMTF values and parse them
  419. // ====================================
  420. CWbemTime wtConst, wtProp;
  421. if(!wtConst.SetDMTF(wszConstValDMTF))
  422. return INVALID;
  423. if(!wtProp.SetDMTF(V_BSTR(&PropVal)))
  424. return INVALID;
  425. __int64 i64Const = wtConst.Get100nss();
  426. __int64 i64Prop = wtProp.Get100nss();
  427. switch (Tok.nOperator)
  428. {
  429. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (i64Prop == i64Const);
  430. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
  431. return (i64Prop != i64Const);
  432. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
  433. return (i64Prop >= i64Const);
  434. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
  435. return (i64Prop <= i64Const);
  436. case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
  437. return (i64Prop < i64Const);
  438. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
  439. return (i64Prop > i64Const);
  440. case QL_LEVEL_1_TOKEN::OP_LIKE: return (i64Prop == i64Const);
  441. }
  442. }
  443. // Coerce types to match.
  444. // ======================
  445. if(V_VT(&CompVal) != VT_NULL && V_VT(&PropVal) != VT_NULL)
  446. {
  447. // Compensate for VT_UI1 > VT_I4
  448. //
  449. if (V_VT(&CompVal) == VT_UI1 && V_VT(&PropVal) !=VT_UI1)
  450. hRes = VariantChangeType(&CompVal,&CompVal,0, VT_I4);
  451. if (V_VT(&PropVal) == VT_UI1 && V_VT(&CompVal) !=VT_UI1)
  452. hRes = VariantChangeType(&PropVal,&PropVal,0, VT_I4);
  453. if (V_VT(&PropVal) > V_VT(&CompVal))
  454. hRes = VariantChangeType(&CompVal, &CompVal, 0, V_VT(&PropVal));
  455. else
  456. hRes = VariantChangeType(&PropVal, &PropVal, 0, V_VT(&CompVal));
  457. if(FAILED(hRes))
  458. {
  459. return INVALID;
  460. }
  461. }
  462. switch (V_VT(&CompVal))
  463. {
  464. case VT_NULL:
  465. return INVALID; // handled above
  466. case VT_I4:
  467. {
  468. if(V_VT(&PropVal) == VT_NULL)
  469. return INVALID;
  470. LONG va = V_I4(&PropVal);
  471. LONG vb = V_I4(&CompVal);
  472. switch (Tok.nOperator)
  473. {
  474. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  475. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  476. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
  477. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
  478. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
  479. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
  480. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  481. }
  482. }
  483. break;
  484. case VT_I2:
  485. {
  486. if(V_VT(&PropVal) == VT_NULL)
  487. return INVALID;
  488. short va = V_I2(&PropVal);
  489. short vb = V_I2(&CompVal);
  490. switch (Tok.nOperator)
  491. {
  492. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  493. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  494. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
  495. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
  496. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
  497. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
  498. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  499. }
  500. }
  501. break;
  502. case VT_UI1:
  503. {
  504. if(V_VT(&PropVal) == VT_NULL)
  505. return INVALID;
  506. BYTE va = V_I1(&PropVal);
  507. BYTE vb = V_I1(&CompVal);
  508. switch (Tok.nOperator)
  509. {
  510. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  511. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  512. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
  513. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
  514. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
  515. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
  516. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  517. }
  518. }
  519. break;
  520. case VT_BSTR:
  521. {
  522. if(V_VT(&PropVal) == VT_NULL)
  523. return INVALID;
  524. LPWSTR va = (LPWSTR) V_BSTR(&PropVal);
  525. LPWSTR vb = (LPWSTR) V_BSTR(&CompVal);
  526. int retCode = 0;
  527. BOOL bDidIt = TRUE;
  528. switch (Tok.nOperator)
  529. {
  530. case QL_LEVEL_1_TOKEN::OP_EQUAL:
  531. retCode = ( wbem_wcsicmp(va,vb) == 0);
  532. break;
  533. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
  534. retCode = (wbem_wcsicmp(va, vb) != 0);
  535. break;
  536. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
  537. retCode = (wbem_wcsicmp(va, vb) >= 0);
  538. break;
  539. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
  540. retCode = (wbem_wcsicmp(va, vb) <= 0);
  541. break;
  542. case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
  543. retCode = (wbem_wcsicmp(va, vb) < 0);
  544. break;
  545. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
  546. retCode = (wbem_wcsicmp(va, vb) > 0);
  547. break;
  548. case QL_LEVEL_1_TOKEN::OP_LIKE:
  549. {
  550. CLike l (vb);
  551. retCode = (int)l.Match(va);
  552. }
  553. break;
  554. default:
  555. bDidIt = FALSE;
  556. break;
  557. }
  558. VariantClear(&CompVal);
  559. if (bDidIt)
  560. {
  561. return retCode;
  562. }
  563. }
  564. break;
  565. case VT_R8:
  566. {
  567. if(V_VT(&PropVal) == VT_NULL)
  568. return INVALID;
  569. double va = V_R8(&PropVal);
  570. double vb = V_R8(&CompVal);
  571. switch (Tok.nOperator)
  572. {
  573. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  574. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  575. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
  576. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
  577. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
  578. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
  579. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  580. }
  581. }
  582. break;
  583. case VT_R4:
  584. {
  585. if(V_VT(&PropVal) == VT_NULL)
  586. return INVALID;
  587. float va = V_R4(&PropVal);
  588. float vb = V_R4(&CompVal);
  589. switch (Tok.nOperator)
  590. {
  591. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  592. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  593. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
  594. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
  595. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
  596. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
  597. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  598. }
  599. }
  600. break;
  601. case VT_BOOL:
  602. {
  603. if(V_VT(&PropVal) == VT_NULL)
  604. return INVALID;
  605. VARIANT_BOOL va = V_BOOL(&PropVal);
  606. if(va != VARIANT_FALSE) va = VARIANT_TRUE;
  607. VARIANT_BOOL vb = V_BOOL(&CompVal);
  608. if(vb != VARIANT_FALSE) vb = VARIANT_TRUE;
  609. switch (Tok.nOperator)
  610. {
  611. case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
  612. case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
  613. case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return INVALID;
  614. case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return INVALID;
  615. case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return INVALID;
  616. case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return INVALID;
  617. case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
  618. }
  619. }
  620. break;
  621. }
  622. return FALSE;
  623. }
  624. //***************************************************************************
  625. //
  626. //***************************************************************************
  627. STDMETHODIMP CQlFilteringSink::SetStatus(
  628. long lFlags,
  629. long lParam,
  630. BSTR strParam,
  631. IWbemClassObject* pObjParam
  632. )
  633. {
  634. if(lFlags == WBEM_STATUS_REQUIREMENTS)
  635. {
  636. m_bFilterNow = (lParam == S_OK);
  637. return WBEM_S_NO_ERROR;
  638. }
  639. else
  640. {
  641. return CFilteringSink::SetStatus(lFlags, lParam, strParam, pObjParam);
  642. }
  643. }
  644. //***************************************************************************
  645. //
  646. //***************************************************************************
  647. CProjectingSink::CProjectingSink(
  648. CBasicObjectSink* pDest,
  649. CWbemClass* pClassDef,
  650. READONLY QL_LEVEL_1_RPN_EXPRESSION* pExp,
  651. long lQueryFlags
  652. )
  653. : CForwardingSink(pDest, 0), m_bValid(FALSE), m_bProjecting(FALSE)
  654. {
  655. // Extract the properties selected by the user.
  656. // ============================================
  657. CWStringArray awsPropList;
  658. for (int i = 0; i < pExp->nNumberOfProperties; i++)
  659. {
  660. CPropertyName& PropName = pExp->pRequestedPropertyNames[i];
  661. LPWSTR wszPrimaryName = CQueryEngine::GetPrimaryName(PropName);
  662. if (wszPrimaryName && !wbem_wcsicmp(wszPrimaryName, L"count(*)"))
  663. {
  664. m_bValid = TRUE;
  665. m_bProjecting = FALSE;
  666. return;
  667. }
  668. // Check for complexity
  669. // ====================
  670. if(PropName.GetNumElements() > 1)
  671. {
  672. // Complex --- make sure the property is an object
  673. // ===============================================
  674. CIMTYPE ct;
  675. if(FAILED(pClassDef->GetPropertyType(wszPrimaryName, &ct)) ||
  676. ct != CIM_OBJECT)
  677. {
  678. m_wsError = wszPrimaryName;
  679. return;
  680. }
  681. }
  682. if (CFlexArray::no_error != awsPropList.Add(wszPrimaryName))
  683. {
  684. return;
  685. }
  686. }
  687. if (awsPropList.Size() == 0)
  688. {
  689. m_bValid = TRUE;
  690. return;
  691. }
  692. if(lQueryFlags & WBEM_FLAG_ENSURE_LOCATABLE)
  693. {
  694. if (CFlexArray::no_error != awsPropList.Add(L"__PATH"))
  695. {
  696. return;
  697. };
  698. }
  699. // Verify that the projection will succeed.
  700. // ========================================
  701. m_wsError = pClassDef->FindLimitationError(0, &awsPropList);
  702. if(m_wsError.Length() > 0)
  703. return;
  704. // Check for *
  705. // ===========
  706. if(pExp->bStar)
  707. {
  708. m_bValid = TRUE;
  709. return;
  710. }
  711. // Map the limitaiton
  712. // ==================
  713. m_bValid = pClassDef->MapLimitation(0, &awsPropList, &m_Map);
  714. m_bProjecting = TRUE;
  715. }
  716. //***************************************************************************
  717. //
  718. //***************************************************************************
  719. STDMETHODIMP CProjectingSink::Indicate(
  720. long lObjectCount,
  721. IWbemClassObject** pObjArray
  722. )
  723. {
  724. if(!m_bProjecting)
  725. return m_pDest->Indicate(lObjectCount, pObjArray);
  726. wmilib::auto_buffer<IWbemClassObject*> apNewArray(new IWbemClassObject*[lObjectCount]);
  727. if (NULL == apNewArray.get())
  728. return WBEM_E_OUT_OF_MEMORY;
  729. HRESULT hres;
  730. int i;
  731. {
  732. CInCritSec ics(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
  733. for(i = 0; i < lObjectCount; i++)
  734. {
  735. CWbemInstance* pInst = (CWbemInstance*)pObjArray[i];
  736. CWbemInstance* pNewInst;
  737. hres = pInst->GetLimitedVersion(&m_Map, &pNewInst);
  738. if(FAILED(hres))
  739. {
  740. for(int j = 0; j < i; j++)
  741. apNewArray[j]->Release();
  742. return hres;
  743. }
  744. apNewArray[i] = pNewInst;
  745. }
  746. }
  747. hres = m_pDest->Indicate(lObjectCount, (IWbemClassObject**)apNewArray.get());
  748. for(i = 0; i < lObjectCount; i++)
  749. apNewArray[i]->Release();
  750. return hres;
  751. }
  752. //***************************************************************************
  753. //
  754. // class CMerger
  755. //
  756. // This class is a 'reverse fork'. It consumes two sinks and outputs
  757. // one. Its purpose is to merge instances of the same key in a given
  758. // dynasty. Each CMerger has two inputs, (a) instances of the class
  759. // in question, (b) instances of from another Merger representing
  760. // instances of subclasses. Given classes A,B:A,C:B, for example,
  761. // where "<--" is a sink:
  762. //
  763. // | own:Instances of A
  764. // <---| | own:Instances of B
  765. // | child: <--------|
  766. // | child:Instances of C
  767. //
  768. //
  769. // The two input sinks for CMerger are <m_pOwnSink> which receives
  770. // instances from the provider for "A", for example, and the <m_pChildSink>
  771. // which receives instances from the underyling Merger.
  772. //
  773. // The mergers operate asynchronously to each other. Therefore,
  774. // the instances for A may arrive in its CMerger sink before instances
  775. // of the child classes have arrived in theirs.
  776. //
  777. // As objects arrive in the owning CMerger for a class, AddOwnObject()
  778. // is called. As objects arrive from a child sink, AddChildObject()
  779. // is called. In either case, if the object with a given key
  780. // arrives for the first time, it is simply added to the map. If
  781. // it is already there (via a key lookup), then a merge is performed
  782. // via CWbemInstance::AsymmetricMerge. Immediately after this merge,
  783. // the object is dispatched up to the next parent sink via the parent's
  784. // AddChildObject and removed from the map.
  785. //
  786. // Note that in a class hierarchy {A,B:A,C:B} an enumeration/query is
  787. // performed only against the classes in the CDynasty referenced in
  788. // the query. This logic occurs in CQueryEngine::EvaluateSubQuery.
  789. // For example, if "select * from B" is the query, only queries
  790. // for B and C are performed. The CMerger logic will do individual
  791. // 'get object' calls for any instances needed in A to complete
  792. // the merged B/C instances while merging is taking place.
  793. //
  794. //***************************************************************************
  795. typedef map<WString, CMerger::CRecord, WSiless, wbem_allocator<CMerger::CRecord> >::iterator TMapIterator;
  796. #pragma warning(disable:4355)
  797. CMerger::CMerger(
  798. CBasicObjectSink* pDest,
  799. CWbemClass* pOwnClass,
  800. CWbemNamespace* pNamespace,
  801. IWbemContext* pContext
  802. )
  803. : m_pDest(pDest), m_bOwnDone(FALSE),
  804. m_bChildrenDone(FALSE), m_pNamespace(pNamespace), m_pContext(pContext),
  805. m_pOwnClass(pOwnClass), m_bDerivedFromTarget(TRUE), m_lRef(0),
  806. m_pSecurity(NULL)
  807. {
  808. m_pOwnSink = new COwnSink(this);
  809. m_pChildSink = new CChildSink(this);
  810. // IsValid will check for these allocation failures
  811. m_pDest->AddRef();
  812. if(m_pContext)
  813. m_pContext->AddRef();
  814. if(m_pNamespace)
  815. m_pNamespace->AddRef();
  816. if(m_pOwnClass)
  817. {
  818. m_pOwnClass->AddRef();
  819. CVar v;
  820. pOwnClass->GetClassName(&v);
  821. m_wsClass = v.GetLPWSTR();
  822. }
  823. // Retrieve call security. Need to create a copy for use on another thread
  824. // =======================================================================
  825. m_pSecurity = CWbemCallSecurity::MakeInternalCopyOfThread();
  826. }
  827. //***************************************************************************
  828. //
  829. //***************************************************************************
  830. CMerger::~CMerger()
  831. {
  832. m_pDest->Release();
  833. if(m_pNamespace)
  834. m_pNamespace->Release();
  835. if(m_pContext)
  836. m_pContext->Release();
  837. if(m_pOwnClass)
  838. m_pOwnClass->Release();
  839. delete m_pOwnSink;
  840. delete m_pChildSink;
  841. if(m_pSecurity)
  842. m_pSecurity->Release();
  843. }
  844. //***************************************************************************
  845. //
  846. //***************************************************************************
  847. long CMerger::AddRef()
  848. {
  849. return InterlockedIncrement(&m_lRef);
  850. }
  851. //***************************************************************************
  852. //
  853. //***************************************************************************
  854. long CMerger::Release()
  855. {
  856. long lRef = InterlockedDecrement(&m_lRef);
  857. if(lRef == 0)
  858. delete this;
  859. return lRef;
  860. }
  861. //***************************************************************************
  862. //
  863. //***************************************************************************
  864. void CMerger::GetKey(IWbemClassObject* pObj, WString& wsKey)
  865. {
  866. LPWSTR wszRelPath = ((CWbemInstance*)pObj)->GetRelPath();
  867. if (wszRelPath == NULL)
  868. {
  869. ERRORTRACE((LOG_WBEMCORE, "Object with no path submitted to a "
  870. "merge\n"));
  871. wsKey.Empty();
  872. return;
  873. }
  874. WCHAR* pwcDot = wcschr(wszRelPath, L'.');
  875. if (pwcDot == NULL)
  876. {
  877. ERRORTRACE((LOG_WBEMCORE, "Object with invalid path %S submitted to a "
  878. "merge\n", wszRelPath));
  879. wsKey.Empty();
  880. // Clean up the path
  881. delete [] wszRelPath;
  882. return;
  883. }
  884. wsKey = pwcDot+1;
  885. delete [] wszRelPath;
  886. }
  887. //***************************************************************************
  888. //
  889. //***************************************************************************
  890. void CMerger::SetIsDerivedFromTarget(BOOL bIs)
  891. {
  892. m_bDerivedFromTarget = bIs;
  893. if (!bIs)
  894. {
  895. // We will need our OwnSink for GetObject calls
  896. // ============================================
  897. m_pOwnSink->AddRef();
  898. }
  899. }
  900. //***************************************************************************
  901. //
  902. //***************************************************************************
  903. HRESULT CMerger::AddOwnObject(IWbemClassObject* pObj)
  904. {
  905. WString wsKey;
  906. GetKey(pObj, wsKey);
  907. CInCritSec ics(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
  908. TMapIterator it = m_map.find(wsKey);
  909. if (it == m_map.end())
  910. {
  911. // Not there. Check if there is any hope for children
  912. // ==================================================
  913. if (m_bChildrenDone)
  914. {
  915. if (m_bDerivedFromTarget)
  916. {
  917. // forward
  918. m_pDest->Add(pObj);
  919. }
  920. else
  921. {
  922. // ignore
  923. }
  924. }
  925. else
  926. {
  927. try
  928. {
  929. // Insert
  930. CRecord& rRecord = m_map[wsKey];
  931. rRecord.m_pData = (CWbemInstance*) pObj;
  932. pObj->AddRef();
  933. rRecord.m_bOwn = TRUE;
  934. }
  935. catch( CX_Exception &)
  936. {
  937. return WBEM_E_OUT_OF_MEMORY;
  938. }
  939. }
  940. }
  941. else
  942. {
  943. // Attempt to merge
  944. // ================
  945. HRESULT hres = CWbemInstance::AsymmetricMerge(
  946. (CWbemInstance*)pObj,
  947. (CWbemInstance*)it->second.m_pData);
  948. if(FAILED(hres))
  949. {
  950. ERRORTRACE((LOG_WBEMCORE, "Merge conflict for instances with "
  951. "key %S\n", wsKey));
  952. }
  953. // Dispatch the result!
  954. // ====================
  955. m_pDest->Add(it->second.m_pData);
  956. it->second.m_pData->Release();
  957. m_map.erase(it);
  958. }
  959. return WBEM_S_NO_ERROR;
  960. }
  961. //***************************************************************************
  962. //
  963. //***************************************************************************
  964. HRESULT CMerger::AddChildObject(IWbemClassObject* pObj)
  965. {
  966. HRESULT hRes = S_OK ;
  967. WString wsKey;
  968. GetKey(pObj, wsKey);
  969. CInCritSec ics(&m_cs); // SEC:REVIEWED 2002-03-22 : Assumes entry
  970. TMapIterator it = m_map.find(wsKey);
  971. if (it == m_map.end())
  972. {
  973. // Check if there is any hope for parent
  974. // =====================================
  975. if(m_bOwnDone)
  976. {
  977. BSTR str = NULL;
  978. pObj->GetObjectText(0, &str);
  979. // The following was commented out because it actually incorrectly logs
  980. // an error if the child provider enumerates when the parent provider
  981. // interprets a query and returns fewer instances. Neither provider is wrong,
  982. // but this error message causes needless worry. In Quasar, we have to fix
  983. // this whole merger thing to be smarter anyway.
  984. //
  985. // ERRORTRACE((LOG_WBEMCORE, "[Chkpt_1] [%S] Orphaned object %S returned by "
  986. // "provider\n", LPWSTR(m_wsClass), str));
  987. SysFreeString(str);
  988. // m_pDest->Add(pObj);
  989. }
  990. else
  991. {
  992. // insert
  993. try
  994. {
  995. CRecord& rRecord = m_map[wsKey];
  996. rRecord.m_pData = (CWbemInstance*)pObj;
  997. pObj->AddRef();
  998. rRecord.m_bOwn = FALSE;
  999. // Check if parent's retrieval is needed
  1000. // =====================================
  1001. if (!m_bDerivedFromTarget)
  1002. {
  1003. try
  1004. {
  1005. GetOwnInstance(wsKey);
  1006. }
  1007. catch( CX_MemoryException &)
  1008. {
  1009. hRes = WBEM_E_OUT_OF_MEMORY;
  1010. }
  1011. catch (...)
  1012. {
  1013. ExceptionCounter c;
  1014. hRes = WBEM_E_CRITICAL_ERROR;
  1015. }
  1016. /*
  1017. * return here because exclusion area has already been exited.
  1018. */
  1019. return hRes ;
  1020. }
  1021. }
  1022. catch( CX_MemoryException &)
  1023. {
  1024. hRes = WBEM_E_OUT_OF_MEMORY;
  1025. }
  1026. catch(...)
  1027. {
  1028. ExceptionCounter c;
  1029. hRes = WBEM_E_CRITICAL_ERROR;
  1030. }
  1031. }
  1032. }
  1033. else if(!it->second.m_bOwn)
  1034. {
  1035. ERRORTRACE((LOG_WBEMCORE, "Two providers supplied conflicting "
  1036. "instances for key %S\n", wsKey));
  1037. }
  1038. else
  1039. {
  1040. // Attempt to merge
  1041. // ================
  1042. IWbemClassObject* pClone;
  1043. HRESULT hres = pObj->Clone(&pClone);
  1044. if (FAILED(hres))
  1045. {
  1046. ERRORTRACE((LOG_WBEMCORE, "Clone failed in AddChildObject, hresult is 0x%x",
  1047. hres));
  1048. return hres;
  1049. }
  1050. hres = CWbemInstance::AsymmetricMerge(
  1051. (CWbemInstance*)it->second.m_pData,
  1052. (CWbemInstance*)pClone
  1053. );
  1054. if (FAILED(hres))
  1055. {
  1056. ERRORTRACE((LOG_WBEMCORE, "Merge conflict for instances with "
  1057. "key %S\n", wsKey));
  1058. }
  1059. // Dispatch the result!
  1060. // ====================
  1061. m_pDest->Add(pClone);
  1062. pClone->Release();
  1063. it->second.m_pData->Release();
  1064. m_map.erase(it);
  1065. }
  1066. return WBEM_S_NO_ERROR;
  1067. }
  1068. //***************************************************************************
  1069. //
  1070. //***************************************************************************
  1071. void CMerger::DispatchChildren()
  1072. {
  1073. TMapIterator it = m_map.begin();
  1074. while (it != m_map.end())
  1075. {
  1076. if (!it->second.m_bOwn)
  1077. {
  1078. BSTR str = NULL;
  1079. it->second.m_pData->GetObjectText(0, &str);
  1080. // The following was commented out because it actually incorrectly logs
  1081. // an error if the child provider enumerates when the parent provider
  1082. // interprets a query and returns fewer instances. Neither provider is wrong,
  1083. // but this error message causes needless worry. In Quasar, we have to fix
  1084. // this whole merger thing to be smarter anyway.
  1085. //
  1086. // ERRORTRACE((LOG_WBEMCORE, "Chkpt2 [%S] Orphaned object %S returned by "
  1087. // "provider\n", LPWSTR(m_wsClass), str));
  1088. SysFreeString(str);
  1089. // m_pDest->Add(it->second.m_pData);
  1090. it->second.m_pData->Release();
  1091. it = m_map.erase(it);
  1092. }
  1093. else it++;
  1094. }
  1095. }
  1096. //***************************************************************************
  1097. //
  1098. //***************************************************************************
  1099. void CMerger::DispatchOwn()
  1100. {
  1101. if(!m_bDerivedFromTarget)
  1102. return;
  1103. try
  1104. {
  1105. TMapIterator it = m_map.begin();
  1106. while (it != m_map.end())
  1107. {
  1108. if(it->second.m_bOwn)
  1109. {
  1110. m_pDest->Add(it->second.m_pData);
  1111. it->second.m_pData->Release();
  1112. it = m_map.erase(it);
  1113. }
  1114. else it++;
  1115. }
  1116. }
  1117. catch(...)
  1118. {
  1119. ExceptionCounter c;
  1120. }
  1121. }
  1122. //***************************************************************************
  1123. //
  1124. //***************************************************************************
  1125. // SEC:REVIEWED 2002-03-22 : This whole function needs a rewrite
  1126. void CMerger::GetOwnInstance(LPCWSTR wszKey)
  1127. {
  1128. size_t tmpLength = wcslen(wszKey) + m_wsClass.Length() + 2; // SEC:REVIEWED 2002-03-22 : Needs EH
  1129. WCHAR * wszPath = new WCHAR[tmpLength];
  1130. CVectorDeleteMe<WCHAR> dm(wszPath);
  1131. if (wszPath && wcslen(wszKey)) // SEC:REVIEWED 2002-03-22 : Needs EH
  1132. {
  1133. StringCchPrintf(wszPath, tmpLength, L"%s.%s", (LPCWSTR)m_wsClass, wszKey);
  1134. {
  1135. HRESULT hr;
  1136. IServerSecurity * pSec = NULL;
  1137. hr = CoGetCallContext(IID_IServerSecurity,(void **)&pSec);
  1138. CReleaseMe rmSec(pSec);
  1139. if (RPC_E_CALL_COMPLETE == hr ) hr = S_OK; // no call context
  1140. if (FAILED(hr)) return;
  1141. BOOL bImper = (pSec)?pSec->IsImpersonating():FALSE;
  1142. if (pSec && bImper && FAILED(hr = pSec->RevertToSelf())) return;
  1143. // implant a call context
  1144. IUnknown* pOld;
  1145. // fails only if COM not initialized on the thread
  1146. if (FAILED(CoSwitchCallContext(m_pSecurity, &pOld))) return;
  1147. hr = m_pNamespace->DynAux_GetSingleInstance(m_pOwnClass, 0, wszPath,m_pContext, m_pOwnSink);
  1148. // remove the planted call context
  1149. IUnknown* pThis;
  1150. CoSwitchCallContext(pOld, &pThis);
  1151. if (bImper && pSec)
  1152. {
  1153. HRESULT hrInner = pSec->ImpersonateClient();
  1154. if (FAILED(hrInner)) throw CX_Exception();
  1155. }
  1156. }
  1157. }
  1158. }
  1159. //***************************************************************************
  1160. //
  1161. //***************************************************************************
  1162. void CMerger::OwnIsDone()
  1163. {
  1164. m_bOwnDone = TRUE;
  1165. m_pOwnSink = NULL;
  1166. }
  1167. //***************************************************************************
  1168. //
  1169. //***************************************************************************
  1170. void CMerger::ChildrenAreDone()
  1171. {
  1172. m_bChildrenDone = TRUE;
  1173. m_pChildSink = NULL;
  1174. if(!m_bDerivedFromTarget)
  1175. {
  1176. // Don't need that ref count on pOwnSink anymore
  1177. // =============================================
  1178. m_pOwnSink->Release();
  1179. }
  1180. }
  1181. //***************************************************************************
  1182. //
  1183. //***************************************************************************
  1184. STDMETHODIMP CMerger::CMemberSink::
  1185. SetStatus(long lFlags, long lParam, BSTR strParam, IWbemClassObject* pObjParam)
  1186. {
  1187. if(lFlags == 0 && lParam == WBEM_E_NOT_FOUND)
  1188. lParam = WBEM_S_NO_ERROR;
  1189. // Propagate error to error combining sink
  1190. // =======================================
  1191. return m_pMerger->m_pDest->SetStatus(lFlags, lParam, strParam,
  1192. pObjParam);
  1193. }
  1194. //***************************************************************************
  1195. //
  1196. //***************************************************************************
  1197. CMerger::COwnSink::~COwnSink()
  1198. {
  1199. m_pMerger->Enter();
  1200. m_pMerger->DispatchChildren();
  1201. m_pMerger->OwnIsDone();
  1202. if (m_pMerger->Release())
  1203. m_pMerger->Leave();
  1204. }
  1205. //***************************************************************************
  1206. //
  1207. //***************************************************************************
  1208. STDMETHODIMP CMerger::COwnSink::
  1209. Indicate(long lNumObjects, IWbemClassObject** apObjects)
  1210. {
  1211. HRESULT hr = WBEM_S_NO_ERROR;
  1212. for(long l = 0; SUCCEEDED( hr ) && l < lNumObjects; l++)
  1213. {
  1214. hr = m_pMerger->AddOwnObject(apObjects[l]);
  1215. }
  1216. return hr;
  1217. }
  1218. //***************************************************************************
  1219. //
  1220. //***************************************************************************
  1221. CMerger::CChildSink::~CChildSink()
  1222. {
  1223. m_pMerger->Enter();
  1224. m_pMerger->DispatchOwn();
  1225. m_pMerger->ChildrenAreDone();
  1226. if(m_pMerger->Release())
  1227. m_pMerger->Leave();
  1228. }
  1229. //***************************************************************************
  1230. //
  1231. //***************************************************************************
  1232. STDMETHODIMP CMerger::CChildSink::Indicate(long lNumObjects, IWbemClassObject** apObjects)
  1233. {
  1234. HRESULT hr = WBEM_S_NO_ERROR;
  1235. for (long l = 0; SUCCEEDED( hr ) && l < lNumObjects; l++)
  1236. {
  1237. hr = m_pMerger->AddChildObject(apObjects[l]);
  1238. }
  1239. return hr;
  1240. }
  1241. //***************************************************************************
  1242. //
  1243. //***************************************************************************
  1244. CProjectionRule* CProjectionRule::Find(LPCWSTR wszName)
  1245. {
  1246. for(int i = 0; i < m_apPropRules.GetSize(); i++)
  1247. {
  1248. if(!wbem_wcsicmp(m_apPropRules[i]->m_wsPropName, wszName))
  1249. return m_apPropRules[i];
  1250. }
  1251. return NULL;
  1252. }
  1253. //***************************************************************************
  1254. //
  1255. //***************************************************************************
  1256. CComplexProjectionSink::CComplexProjectionSink(CBasicObjectSink* pDest,
  1257. CWQLScanner * pParser)
  1258. : CForwardingSink(pDest)
  1259. {
  1260. m_TopRule.m_eType = CProjectionRule::e_TakePart;
  1261. bool bFirstTableEntry = true;
  1262. CWStringArray awsTables;
  1263. pParser->GetReferencedAliases(awsTables);
  1264. WString wsPrefix;
  1265. if(awsTables.Size() == 0)
  1266. {
  1267. m_TopRule.m_eType = CProjectionRule::e_TakeAll;
  1268. return;
  1269. }
  1270. else if(awsTables.Size() == 1)
  1271. {
  1272. wsPrefix = awsTables[0]; // throw
  1273. }
  1274. // Extract projection rules from the parser
  1275. // ========================================
  1276. const CFlexArray* papColumns = pParser->GetSelectedColumns();
  1277. if(papColumns == NULL)
  1278. return;
  1279. for(int i = 0; i < papColumns->Size(); i++)
  1280. {
  1281. SWQLColRef* pColRef = (SWQLColRef*)papColumns->GetAt(i);
  1282. if(pColRef->m_dwFlags & WQL_FLAG_ASTERISK)
  1283. {
  1284. m_TopRule.m_eType = CProjectionRule::e_TakeAll;
  1285. }
  1286. else
  1287. {
  1288. LPWSTR pPrefix = NULL;
  1289. if(pColRef->m_dwFlags & WQL_FLAG_TABLE || pColRef->m_dwFlags & WQL_FLAG_ALIAS)
  1290. {
  1291. if(bFirstTableEntry)
  1292. if(pColRef->m_dwFlags & WQL_FLAG_ALIAS)
  1293. {
  1294. m_FirstTable = pParser->AliasToTable(pColRef->m_pTableRef);
  1295. m_FirstTableAlias = pColRef->m_pTableRef;
  1296. }
  1297. else
  1298. m_FirstTable = pColRef->m_pTableRef;
  1299. pPrefix = pColRef->m_pTableRef;
  1300. bFirstTableEntry = false;
  1301. }
  1302. else if(wsPrefix.Length())
  1303. pPrefix = (LPWSTR)wsPrefix;
  1304. AddColumn(pColRef->m_pQName->m_aFields, pPrefix);
  1305. }
  1306. }
  1307. if(pParser->CountQuery())
  1308. {
  1309. // Add the rule for 'count'
  1310. // ========================
  1311. wmilib::auto_ptr<CProjectionRule> pCountRule( new CProjectionRule(L"count"));
  1312. if (NULL == pCountRule.get()) throw CX_MemoryException();
  1313. pCountRule->m_eType = CProjectionRule::e_TakeAll;
  1314. if (CFlexArray::no_error != m_TopRule.m_apPropRules.Add(pCountRule.get()))
  1315. throw CX_MemoryException();
  1316. pCountRule.release();
  1317. }
  1318. };
  1319. //***************************************************************************
  1320. //
  1321. //***************************************************************************
  1322. void CComplexProjectionSink::AddColumn(CFlexArray& aFields, LPCWSTR wszPrefix)
  1323. {
  1324. CProjectionRule* pCurrentRule = &m_TopRule;
  1325. for(int i = 0; i < aFields.Size(); i++)
  1326. {
  1327. SWQLQualifiedNameField* pField = (SWQLQualifiedNameField*)aFields[i];
  1328. if(!wcscmp(pField->m_pName, L"*"))
  1329. {
  1330. pCurrentRule->m_eType = CProjectionRule::e_TakeAll;
  1331. return;
  1332. }
  1333. if(i == 0 && wszPrefix && !wbem_wcsicmp(pField->m_pName, wszPrefix) && aFields.Size() ==1)
  1334. {
  1335. // Skip this part because it is nothing more that a class name
  1336. // in a single-class query
  1337. // ===========================================================
  1338. continue;
  1339. }
  1340. // Look this column up in the rule
  1341. // ===============================
  1342. CProjectionRule* pNewRule = pCurrentRule->Find(pField->m_pName);
  1343. if(pNewRule == NULL)
  1344. {
  1345. pNewRule = new CProjectionRule(pField->m_pName);
  1346. if (pNewRule)
  1347. {
  1348. pNewRule->m_eType = CProjectionRule::e_TakePart;
  1349. if (pCurrentRule->m_apPropRules.Add(pNewRule) < 0)
  1350. {
  1351. delete pNewRule;
  1352. pNewRule = NULL;
  1353. }
  1354. }
  1355. }
  1356. pCurrentRule = pNewRule; // possible assign to NULL
  1357. }
  1358. // Mark this rule as take-all
  1359. // ==========================
  1360. if (pCurrentRule)
  1361. pCurrentRule->m_eType = CProjectionRule::e_TakeAll;
  1362. }
  1363. //***************************************************************************
  1364. //
  1365. //***************************************************************************
  1366. CComplexProjectionSink::~CComplexProjectionSink()
  1367. {
  1368. }
  1369. //***************************************************************************
  1370. //
  1371. //***************************************************************************
  1372. STDMETHODIMP CComplexProjectionSink::Indicate(long lObjectCount,
  1373. IWbemClassObject** pObjArray)
  1374. {
  1375. HRESULT hres;
  1376. IWbemClassObject** apProjected = new IWbemClassObject*[lObjectCount];
  1377. if (NULL == apProjected)
  1378. return WBEM_E_OUT_OF_MEMORY;
  1379. int i;
  1380. for(i = 0; i < lObjectCount; i++)
  1381. {
  1382. hres = Project(pObjArray[i], &m_TopRule, apProjected + i);
  1383. if(FAILED(hres))
  1384. {
  1385. ERRORTRACE((LOG_WBEMCORE, "Unable to perform a projection of an "
  1386. "object returned by a complex query: 0x%X\n", hres));
  1387. pObjArray[i]->Clone(apProjected + i);
  1388. }
  1389. }
  1390. hres = CForwardingSink::Indicate(lObjectCount, apProjected);
  1391. for(i = 0; i < lObjectCount; i++)
  1392. apProjected[i]->Release();
  1393. delete [] apProjected;
  1394. return hres;
  1395. }
  1396. //***************************************************************************
  1397. //
  1398. //***************************************************************************
  1399. HRESULT CComplexProjectionSink::Project(IWbemClassObject* pObj,
  1400. CProjectionRule* pRule,
  1401. IWbemClassObject** ppProj)
  1402. {
  1403. // Make a copy
  1404. // ===========
  1405. pObj->Clone(ppProj);
  1406. CWbemInstance* pProj = (CWbemInstance*)*ppProj;
  1407. // Take care of the case where the object being returned is a product of a join, but is of single
  1408. // class. Ex; Select Site.sitenmame from Site, NotUsed.
  1409. // This a a problem since we would normally expect a generic object as a result of a join and instead
  1410. // get one of the objects that make up the join.
  1411. CVar v;
  1412. pProj->GetClassName(&v);
  1413. bool Override = !wbem_wcsicmp(m_FirstTable, v.GetLPWSTR());
  1414. if(Override && pRule->GetNumElements() == 1)
  1415. {
  1416. CProjectionRule* pNewRule = NULL;
  1417. if(m_FirstTableAlias.Length())
  1418. pNewRule = pRule->Find(m_FirstTableAlias);
  1419. else
  1420. pNewRule = pRule->Find(m_FirstTable);
  1421. if(pNewRule)
  1422. pRule = pNewRule;
  1423. }
  1424. // If take all, just return
  1425. // ========================
  1426. if(pRule->m_eType == CProjectionRule::e_TakeAll)
  1427. return WBEM_S_NO_ERROR;
  1428. // Go through all its properties
  1429. // =============================
  1430. for(int i = 0; i < pProj->GetNumProperties(); i++)
  1431. {
  1432. CVar vName;
  1433. pProj->GetPropName(i, &vName);
  1434. // Search for this name
  1435. // ====================
  1436. CProjectionRule* pPropRule = pRule->Find(vName.GetLPWSTR());
  1437. if(pPropRule == NULL)
  1438. {
  1439. // Remove the property
  1440. // ===================
  1441. pProj->DeleteProperty(i);
  1442. i--;
  1443. }
  1444. else if(pPropRule->m_eType == CProjectionRule::e_TakePart)
  1445. {
  1446. // Apply the same procedure
  1447. // ========================
  1448. CVar vValue;
  1449. pProj->GetProperty(vName.GetLPWSTR(), &vValue);
  1450. if(vValue.GetType() == VT_EMBEDDED_OBJECT)
  1451. {
  1452. // Project it
  1453. // ==========
  1454. IWbemClassObject* pEmb =
  1455. (IWbemClassObject*)vValue.GetEmbeddedObject();
  1456. IWbemClassObject* pEmbProj;
  1457. HRESULT hres = Project(pEmb, pPropRule, &pEmbProj);
  1458. pEmb->Release();
  1459. // Store it back
  1460. // =============
  1461. if(SUCCEEDED(hres))
  1462. {
  1463. vValue.Empty();
  1464. vValue.SetEmbeddedObject(pEmbProj);
  1465. pProj->SetPropValue(vName.GetLPWSTR(), &vValue, 0);
  1466. pEmbProj->Release();
  1467. }
  1468. }
  1469. }
  1470. }
  1471. pProj->CompactClass();
  1472. return WBEM_S_NO_ERROR;
  1473. }
  1474. //***************************************************************************
  1475. //
  1476. // CQueryEngine::ExecQuery
  1477. //
  1478. // Primary entry point for execution of all queries supported by
  1479. // the query engine.
  1480. //
  1481. //***************************************************************************
  1482. // ok
  1483. HRESULT CQueryEngine::ExecQuery(
  1484. IN CWbemNamespace *pNs,
  1485. IN LPWSTR pszQueryFormat,
  1486. IN LPWSTR pszQuery,
  1487. IN LONG lFlags,
  1488. IN IWbemContext* pContext,
  1489. IN CBasicObjectSink* pSink
  1490. )
  1491. {
  1492. try
  1493. {
  1494. COperationError OpInfo(pSink, L"ExecQuery", pszQuery);
  1495. if (!OpInfo.IsOk()) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1496. if (ConfigMgr::ShutdownInProgress()) return OpInfo.ErrorOccurred(WBEM_E_SHUTTING_DOWN);
  1497. // Check query language
  1498. if(wbem_wcsicmp(pszQueryFormat, L"WQL") != 0) return OpInfo.ErrorOccurred(WBEM_E_INVALID_QUERY_TYPE);
  1499. while (*pszQuery && isspace((WCHAR)*pszQuery)) pszQuery++;
  1500. if (0 == pszQuery[0]) return OpInfo.ErrorOccurred(WBEM_E_INVALID_QUERY);
  1501. // If a prototype query is requested, get the synthesized
  1502. // class definition.
  1503. if (lFlags & WBEM_FLAG_PROTOTYPE)
  1504. {
  1505. return ExecPrototypeQuery(pNs,pszQuery,pContext,pSink);
  1506. }
  1507. WCHAR * pEndToken = pszQuery;
  1508. while (*pEndToken && !isspace((WCHAR)*pEndToken)) pEndToken++;
  1509. size_t SizeToken = (ULONG_PTR)pEndToken - (ULONG_PTR)pszQuery;
  1510. SizeToken /= sizeof(WCHAR);
  1511. // Get the first token of the query to see if it is SQL1 or TEMPQL
  1512. BOOL bSelect = FALSE;
  1513. BOOL bDelete = FALSE;
  1514. if (6 == SizeToken)
  1515. {
  1516. bSelect = (0 == wbem_wcsnicmp(pszQuery, L"select",6));
  1517. bDelete = (0 == wbem_wcsnicmp(pszQuery, L"delete",6));
  1518. }
  1519. CBasicObjectSink *pNewSink = OpInfo.GetSink();
  1520. CLocaleMergingSink *pLocaleSink = NULL;
  1521. if (lFlags & WBEM_FLAG_USE_AMENDED_QUALIFIERS)
  1522. {
  1523. pLocaleSink = new CLocaleMergingSink(pNewSink, pNs->GetLocale(), pNs->GetName());
  1524. if ( NULL == pLocaleSink ) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
  1525. pLocaleSink->AddRef();
  1526. pNewSink = pLocaleSink;
  1527. }
  1528. CReleaseMe rmLocale(pLocaleSink);
  1529. CFinalizingSink* pFinalSink = new CFinalizingSink(pNs, pNewSink);
  1530. if ( NULL == pFinalSink ) return OpInfo.ErrorOccurred(WBEM_E_OUT_OF_MEMORY);
  1531. pFinalSink->AddRef();
  1532. CReleaseMe rmFinal(pFinalSink);
  1533. if (bSelect)
  1534. {
  1535. ExecQlQuery(pNs, pszQuery, lFlags, pContext, pFinalSink);
  1536. }
  1537. else if (bDelete)
  1538. {
  1539. ExecRepositoryQuery(pNs, pszQuery, lFlags, pContext, pFinalSink);
  1540. }
  1541. else // ASSOCIATORS OF or REFERENCES OF query
  1542. {
  1543. CAssocQuery *pAssocQuery = CAssocQuery::CreateInst();
  1544. if (NULL == pAssocQuery)
  1545. {
  1546. return pFinalSink->Return(WBEM_E_OUT_OF_MEMORY);
  1547. }
  1548. CReleaseMe rmAssocQ(pAssocQuery);
  1549. // Execute the query and see what happens.
  1550. // The object AddRefs and Releases itself as required.
  1551. // We only need to do a Release right after Execute.
  1552. // =====================================
  1553. pAssocQuery->Execute(pNs, pszQuery, pContext, pFinalSink);
  1554. }
  1555. }
  1556. catch (CX_Exception &)
  1557. {
  1558. pSink->SetStatus(0, WBEM_E_OUT_OF_MEMORY, 0, 0);
  1559. return WBEM_E_OUT_OF_MEMORY;
  1560. }
  1561. return WBEM_S_NO_ERROR;
  1562. }
  1563. //***************************************************************************
  1564. //
  1565. //***************************************************************************
  1566. HRESULT CQueryEngine::ExecComplexQuery(
  1567. IN CWbemNamespace *pNs,
  1568. IN LPWSTR pszQuery,
  1569. IN LONG lFlags,
  1570. IN IWbemContext* pContext,
  1571. IN CBasicObjectSink* pSink
  1572. )
  1573. {
  1574. // Try to parse it
  1575. // ===============
  1576. CTextLexSource src(pszQuery);
  1577. CWQLScanner Parser(&src);
  1578. int nRes = Parser.Parse();
  1579. if(nRes != CWQLScanner::SUCCESS)
  1580. {
  1581. return WBEM_E_INVALID_QUERY;
  1582. }
  1583. // Successfully parsed. Go to the list of tables involved
  1584. // ======================================================
  1585. CWStringArray awsTables;
  1586. Parser.GetReferencedTables(awsTables);
  1587. // Go through them and check their providers
  1588. // =========================================
  1589. WString wsProvider;
  1590. for(int i = 0; i < awsTables.Size(); i++)
  1591. {
  1592. // Get the class
  1593. IWbemClassObject* pObj = NULL;
  1594. HRESULT hres = pNs->Exec_GetObjectByPath(awsTables[i], lFlags, pContext,&pObj, NULL);
  1595. if(FAILED(hres))
  1596. {
  1597. if(hres == WBEM_E_NOT_FOUND)
  1598. {
  1599. if(!wbem_wcsicmp(awsTables[i], L"meta_class"))
  1600. hres = WBEM_E_INVALID_QUERY;
  1601. else
  1602. hres = WBEM_E_INVALID_CLASS;
  1603. }
  1604. return hres;
  1605. }
  1606. CReleaseMe rmObj(pObj);
  1607. // Check the qualifier
  1608. // ===================
  1609. CWbemClass* pClass = (CWbemClass*)pObj;
  1610. CVar vProvider;
  1611. hres = pClass->GetQualifier(L"provider", &vProvider);
  1612. if(FAILED(hres) ||
  1613. vProvider.GetType() != VT_BSTR ||
  1614. vProvider.GetLPWSTR() == 0 ||
  1615. wcslen(vProvider.GetLPWSTR()) == 0)
  1616. {
  1617. // no provider --- can't execute
  1618. return WBEM_E_INVALID_QUERY;
  1619. }
  1620. if(i == 0)
  1621. {
  1622. wsProvider = vProvider.GetLPWSTR(); // throw
  1623. }
  1624. else
  1625. {
  1626. if(!wsProvider.EqualNoCase(vProvider.GetLPWSTR()))
  1627. {
  1628. // mismatched providers!
  1629. return WBEM_E_INVALID_QUERY;
  1630. }
  1631. }
  1632. }
  1633. CComplexProjectionSink* pProjSink = new CComplexProjectionSink(pSink, &Parser);
  1634. if (NULL == pProjSink) return WBEM_E_OUT_OF_MEMORY;
  1635. pProjSink->AddRef();
  1636. CReleaseMe rm1(pProjSink);
  1637. // All the classes have the same provider: wsProvider
  1638. // ==================================================
  1639. return pNs->DynAux_ExecQueryExtendedAsync(wsProvider,pszQuery,L"WQL" ,lFlags,pContext,pProjSink);
  1640. }
  1641. //
  1642. //
  1643. // CQueryEngine::ExecQlQuery
  1644. //
  1645. // This function MUST call SetStatus if there is an error of it's own
  1646. //
  1647. ///////////////////////////////////////////////////////////////////////////////
  1648. HRESULT CQueryEngine::ExecQlQuery(
  1649. IN CWbemNamespace *pNs,
  1650. IN LPWSTR pszQuery,
  1651. IN LONG lFlags,
  1652. IN IWbemContext* pContext,
  1653. IN CBasicObjectSink* pSink
  1654. )
  1655. {
  1656. HRESULT hRes;
  1657. BOOL bDirectQuery = FALSE;
  1658. BOOL bShallow = (lFlags & WBEM_FLAG_SHALLOW);
  1659. // First, try to push it off to providers,
  1660. // that can handle the query it its entirety.
  1661. // =================================
  1662. if(!bShallow)
  1663. {
  1664. hRes = ExecComplexQuery(pNs, pszQuery, lFlags, pContext, pSink); // throws
  1665. if(SUCCEEDED(hRes))
  1666. return hRes;
  1667. }
  1668. // Parse the query.
  1669. // ================
  1670. CTextLexSource src(pszQuery);
  1671. QL1_Parser parser(&src);
  1672. QL_LEVEL_1_RPN_EXPRESSION *pExp = 0;
  1673. int nRes = parser.Parse(&pExp);
  1674. if (CAbstractQl1Parser::SUCCESS != nRes) return pSink->Return(WBEM_E_INVALID_QUERY);
  1675. _DBG_ASSERT(pExp);
  1676. pExp->AddRef();
  1677. CTemplateReleaseMe<QL_LEVEL_1_RPN_EXPRESSION> trm99(pExp);
  1678. // Check if the repository for this namespace
  1679. // supports queries. If so, we can pawn off
  1680. // the entire query on it (with the exception
  1681. // of provider-backed subclasses)
  1682. // ===========================================
  1683. bDirectQuery = pNs->GetNsSession()->SupportsQueries(NULL) == WBEM_S_NO_ERROR ? TRUE : FALSE;
  1684. if (!bDirectQuery)
  1685. {
  1686. // Check for failure, or that pExp->bAggregated is TRUE, in which
  1687. // case we got a "GROUP BY" query which we do not support
  1688. if ( nRes || pExp->bAggregated || !pExp->bsClassName )
  1689. {
  1690. return pSink->Return(WBEM_E_INVALID_QUERY);
  1691. }
  1692. }
  1693. else
  1694. {
  1695. // This is strictly to allow order by clauses to squeak through,
  1696. // until we replace this parser with IWbemQuery.
  1697. if (!pExp || !pExp->bsClassName || pExp->bAggregated)
  1698. {
  1699. return pSink->Return(WBEM_E_INVALID_QUERY);
  1700. }
  1701. }
  1702. // We should make a check to see if we are doing a schema search. This is
  1703. // the case if we are doing a select against the "meta_class" class.
  1704. // =======================================================================
  1705. if (wbem_wcsicmp(pExp->bsClassName, L"meta_class") == 0)
  1706. {
  1707. if(pExp->nNumberOfProperties > 0 || !pExp->bStar)
  1708. {
  1709. return pSink->Return(WBEM_E_INVALID_QUERY);
  1710. }
  1711. return ExecSchemaQuery(pNs, pszQuery, pExp, pContext, pSink);
  1712. }
  1713. // Build the dynasty
  1714. // =================
  1715. wmilib::auto_ptr<CDynasty> pDynasty;
  1716. IWbemClassObject* pErrorObj = NULL;
  1717. HRESULT hres = pNs->DynAux_BuildClassHierarchy(pExp->bsClassName,
  1718. 0, // removed the flags
  1719. pContext,
  1720. pDynasty,
  1721. &pErrorObj);
  1722. if (FAILED(hres))
  1723. {
  1724. CReleaseMe rm1(pErrorObj);
  1725. if(hres == WBEM_E_NOT_FOUND || hres == WBEM_E_INVALID_CLASS)
  1726. return pSink->Return(WBEM_E_INVALID_CLASS, pErrorObj);
  1727. else
  1728. return pSink->Return(WBEM_E_INVALID_QUERY, pErrorObj);
  1729. }
  1730. // Construct a post-filtering (if needed) and projecting sink
  1731. // ==========================================================
  1732. IWbemClassObject* pClass = NULL;
  1733. CReleaseMeRef<IWbemClassObject*> rm1(pClass);
  1734. if (!pExp->bCount)
  1735. {
  1736. hres = pNs->Exec_GetObjectByPath(pExp->bsClassName, lFlags, pContext, &pClass, NULL);
  1737. if(FAILED(hres))
  1738. {
  1739. return pSink->Return(WBEM_E_INVALID_CLASS);
  1740. }
  1741. }
  1742. else
  1743. {
  1744. if (!bDirectQuery) return pSink->Return(WBEM_E_NOT_SUPPORTED);
  1745. // here it's a Direct Query
  1746. hres = CoCreateInstance(CLSID_WbemClassObject,
  1747. NULL, CLSCTX_INPROC_SERVER,
  1748. IID_IWbemClassObject,
  1749. (void **)&pClass);
  1750. if (FAILED(hres)) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1751. BSTR bstrName = SysAllocString(L"__Generic");
  1752. if (NULL == bstrName) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1753. VARIANT vTemp;
  1754. V_VT(&vTemp) = VT_BSTR;
  1755. V_BSTR(&vTemp) = bstrName;
  1756. _variant_t Var;
  1757. Var.Attach(vTemp);
  1758. hres = pClass->Put(L"__Class", 0, &vTemp, CIM_STRING);
  1759. if (FAILED(hres)) return pSink->Return(hRes);
  1760. hres = pClass->Put(L"Count", 0, NULL, CIM_UINT32);
  1761. if (FAILED(hres)) return pSink->Return(hRes);
  1762. }
  1763. CBasicObjectSink* pPreFilterSink = NULL;
  1764. if(lFlags & WBEM_FLAG_KEEP_SHAPE)
  1765. {
  1766. //
  1767. // We must not project the results, otherwise we will destroy the shape
  1768. // of the instance. Remove the flag, though, lest we confuse providers
  1769. //
  1770. lFlags &= ~WBEM_FLAG_KEEP_SHAPE;
  1771. pPreFilterSink = pSink;
  1772. }
  1773. else
  1774. {
  1775. // this guy throws
  1776. CProjectingSink* pProjectingSink = new CProjectingSink(pSink, (CWbemClass*)pClass, pExp, lFlags);
  1777. if (NULL == pProjectingSink)
  1778. return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1779. if(!pProjectingSink->IsValid())
  1780. {
  1781. delete pProjectingSink;
  1782. return pSink->Return(WBEM_E_INVALID_QUERY);
  1783. }
  1784. pPreFilterSink = pProjectingSink;
  1785. }
  1786. CQlFilteringSink* pFilteringSink = new CQlFilteringSink(pPreFilterSink, pExp, pNs, TRUE);
  1787. if (NULL == pFilteringSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1788. // If shallow, force post-filtering
  1789. // ================================
  1790. if(bShallow) pFilteringSink->SetStatus(WBEM_STATUS_REQUIREMENTS, S_OK, NULL, NULL);
  1791. CCombiningSink* pCombiningSink = new CCombiningSink(pFilteringSink, WBEM_E_NOT_FOUND);
  1792. if (NULL == pCombiningSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1793. CDynPropsSink * pDynSink = new CDynPropsSink(pCombiningSink, pNs);
  1794. if (NULL == pDynSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  1795. pDynSink->AddRef();
  1796. CReleaseMe rm99(pDynSink);
  1797. // We simplify the query if our repository ain't too bright.
  1798. // Otherwise, it will reject count queries.
  1799. // Again, temporary until we get IWbemQuery plugged in.
  1800. if (!bDirectQuery)
  1801. {
  1802. // "Simplify" the query (TBD: think about doing it at each level)
  1803. // ==============================================================
  1804. QL_LEVEL_1_RPN_EXPRESSION* pSimpleExp = NULL;
  1805. CStandardMetaData* pRawMeta = new CStandardMetaData(pNs);
  1806. if (NULL == pRawMeta)
  1807. {
  1808. pDynSink->Return(WBEM_E_OUT_OF_MEMORY);
  1809. return WBEM_S_NO_ERROR;
  1810. }
  1811. CContextMetaData* pMeta = new CContextMetaData(pRawMeta, pContext);
  1812. if (NULL == pMeta)
  1813. {
  1814. delete pRawMeta;
  1815. pDynSink->Return(WBEM_E_OUT_OF_MEMORY);
  1816. return WBEM_S_NO_ERROR;
  1817. }
  1818. hres = CQueryAnalyser::SimplifyQueryForChild(pExp,
  1819. pExp->bsClassName, (CWbemClass*)pClass, pMeta, pSimpleExp);
  1820. delete pMeta;
  1821. if(FAILED(hres))
  1822. {
  1823. pDynSink->Return(WBEM_E_INVALID_QUERY);
  1824. return WBEM_S_NO_ERROR;
  1825. }
  1826. if(pSimpleExp == NULL)
  1827. {
  1828. // Query violated intergrity constraint
  1829. // ====================================
  1830. pDynSink->Return(WBEM_S_NO_ERROR); // ?? WBEM_S_IMPOSSIBLE
  1831. return WBEM_S_NO_ERROR;
  1832. }
  1833. // Substitute the simplified where clause into the query
  1834. // =====================================================
  1835. delete [] pExp->pArrayOfTokens;
  1836. pExp->pArrayOfTokens = pSimpleExp->pArrayOfTokens;
  1837. pExp->nNumTokens = pSimpleExp->nNumTokens;
  1838. pSimpleExp->pArrayOfTokens = NULL;
  1839. delete pSimpleExp;
  1840. }
  1841. // Now make a final pass to make sure this query is valid
  1842. // ======================================================
  1843. hres = ValidateQuery(pExp, (CWbemClass *)pClass);
  1844. if (FAILED(hres))
  1845. {
  1846. pDynSink->Return(hres);
  1847. return WBEM_S_NO_ERROR;
  1848. }
  1849. LPWSTR pszNewQuery = NULL;
  1850. // Preserve the original query if
  1851. // it contains count, order by
  1852. // (or other unparsable stuff)
  1853. if (pExp->bCount || nRes)
  1854. pszNewQuery = Macro_CloneLPWSTR(pszQuery);
  1855. else
  1856. pszNewQuery = pExp->GetText();
  1857. if (NULL == pszNewQuery)
  1858. {
  1859. pDynSink->Return(WBEM_E_OUT_OF_MEMORY);
  1860. return WBEM_S_NO_ERROR;
  1861. }
  1862. CVectorDeleteMe<wchar_t> cdm98(pszNewQuery);
  1863. // If direct access was requested, then don't walk
  1864. // the dynasty. Go right to the repository or the provider.
  1865. // ========================================================
  1866. if (lFlags & WBEM_FLAG_DIRECT_READ)
  1867. {
  1868. DirectRead(pNs, pDynasty.get(), pszNewQuery, pExp, pContext,
  1869. pDynSink, lFlags & ~WBEM_FLAG_ENSURE_LOCATABLE
  1870. );
  1871. }
  1872. else // Recursively execute for all classes in the dynasty
  1873. {
  1874. BOOL fUseOld = !ConfigMgr::GetMergerThrottlingEnabled();
  1875. // Check the Registry
  1876. if ( fUseOld )
  1877. {
  1878. EvaluateSubQuery_old(
  1879. pNs, pDynasty.get(), pszNewQuery, pExp, pContext, FALSE,
  1880. pDynSink, lFlags & ~WBEM_FLAG_ENSURE_LOCATABLE
  1881. );
  1882. }
  1883. else
  1884. {
  1885. // Allocate a new merger and pass it down the line
  1886. CWmiMerger* pMerger = new CWmiMerger( pNs );
  1887. if ( NULL == pMerger ) return pDynSink->Return( WBEM_E_OUT_OF_MEMORY );
  1888. pMerger->AddRef();
  1889. CReleaseMe rmMerger( (_IWmiArbitratee*) pMerger );
  1890. // Task handle will be available if we have an executing request,
  1891. // if not, don't worry about it right now. Nobody's really able
  1892. // to give a straight answer on this, so we will simply add an assert
  1893. // if a merger is created and no task handle is associated with the
  1894. // main merger.
  1895. _IWmiArbitrator* pArbitrator = CWmiArbitrator::GetRefedArbitrator();
  1896. if (NULL == pArbitrator) return pDynSink->Return(WBEM_E_CRITICAL_ERROR);
  1897. CReleaseMe rmArb( pArbitrator );
  1898. _IWmiCoreHandle* pTask = NULL;
  1899. CWbemRequest* pReq = CWbemQueue::GetCurrentRequest();
  1900. if ( pReq )
  1901. {
  1902. pTask = pReq->m_phTask;
  1903. }
  1904. //
  1905. // creates the MergerSink as the DestinationSink
  1906. //
  1907. CMergerSink* pDestSink = NULL;
  1908. HRESULT hr = pMerger->Initialize( pArbitrator, pTask, pExp->bsClassName, pDynSink, &pDestSink );
  1909. CReleaseMe rm( pDestSink );
  1910. if (FAILED(hr)) return pDynSink->Return( hr );
  1911. // If something goes wrong in this function, it will set the
  1912. // error in the sink
  1913. hr = EvaluateSubQuery(pNs, pDynasty.get(),
  1914. pszNewQuery,
  1915. pExp, pContext, FALSE,
  1916. pMerger, pDestSink, lFlags & ~WBEM_FLAG_ENSURE_LOCATABLE);
  1917. if ( SUCCEEDED( hr ) )
  1918. {
  1919. //
  1920. // Schedule a parent request if appropriate
  1921. // The Merger Request Manager knonws if it has one or more requests
  1922. // one request is handled here synchronously
  1923. // more request are kicked off by the MergerParent Request
  1924. // in a different thread of the queue
  1925. //
  1926. hr = pMerger->ScheduleMergerParentRequest( pContext );
  1927. if (FAILED(hr)) return pDestSink->Return( hr );
  1928. }
  1929. }
  1930. }
  1931. return hres;
  1932. }
  1933. //***************************************************************************
  1934. //
  1935. // CQueryEngine::DirectRead
  1936. //
  1937. // Called to directly read the instances of a class, whether
  1938. // from the repository or a provider.
  1939. //
  1940. //***************************************************************************
  1941. HRESULT CQueryEngine::DirectRead(
  1942. IN CWbemNamespace *pNs,
  1943. IN CDynasty *pCurrentDyn,
  1944. IN LPWSTR wszTextQuery,
  1945. IN QL_LEVEL_1_RPN_EXPRESSION *pParsedQuery,
  1946. IN IWbemContext* pContext,
  1947. IN CBasicObjectSink* pSink,
  1948. IN long lFlags
  1949. )
  1950. {
  1951. // SJS - Amendment is the same as Abstract
  1952. if( ( pCurrentDyn->IsAbstract() || pCurrentDyn->IsAmendment() ) && (lFlags & WBEM_FLAG_SHALLOW))
  1953. {
  1954. // No instances
  1955. // ============
  1956. return pSink->Return(WBEM_S_NO_ERROR);
  1957. }
  1958. // The class has its own instances if it has a key and is either dynamic
  1959. // or the first static class in the inheritance chain (otherwise these
  1960. // instances have been handled in the parent)
  1961. // =====================================================================
  1962. BOOL bHasOwnInstances = pCurrentDyn->IsKeyed() && !pCurrentDyn->IsAbstract()
  1963. && !pCurrentDyn->IsAmendment();
  1964. // The class has children that we need to look at if it has children.
  1965. // ==================================================================
  1966. BOOL bHasChildren = (pCurrentDyn->m_Children.Size() > 0);
  1967. // Determine if the current query actually asks for instances of the
  1968. // current CDynasty class. This is used for WBEM_FLAG_DIRECT_READ type
  1969. // access.
  1970. // =======================================================================
  1971. BOOL bQueryMatchesCurrentNode = FALSE;
  1972. if (wbem_wcsicmp(pParsedQuery->bsClassName, pCurrentDyn->m_wszClassName) == 0)
  1973. bQueryMatchesCurrentNode = TRUE;
  1974. // If we are at the node we need, we can stop.
  1975. // ===========================================
  1976. if (bHasOwnInstances && bQueryMatchesCurrentNode)
  1977. {
  1978. // If a provider backs this class, then call it.
  1979. // ==============================================
  1980. if (pCurrentDyn->IsDynamic())
  1981. {
  1982. ExecAtomicDynQlQuery(
  1983. pNs,
  1984. pCurrentDyn,
  1985. L"WQL",
  1986. wszTextQuery,
  1987. pParsedQuery,
  1988. lFlags, // Flags
  1989. pContext,
  1990. pSink,
  1991. FALSE
  1992. );
  1993. }
  1994. // Try the repository.
  1995. // ===================
  1996. else
  1997. {
  1998. int nRes = ExecAtomicDbQuery(pNs->GetNsSession(), pNs->GetNsHandle(), pNs->GetScope(), pCurrentDyn->m_wszClassName,
  1999. pParsedQuery, pSink, pNs
  2000. );
  2001. if (nRes == invalid_query)
  2002. pSink->Return(WBEM_E_INVALID_QUERY);
  2003. else if(nRes != 0)
  2004. pSink->Return(WBEM_E_FAILED);
  2005. else
  2006. pSink->Return(WBEM_S_NO_ERROR);
  2007. }
  2008. }
  2009. // If here, we must keep looking for the target in the child classes.
  2010. // ==================================================================
  2011. else if (bHasChildren)
  2012. {
  2013. for (int i = 0; i < pCurrentDyn->m_Children.Size(); i++)
  2014. {
  2015. CDynasty *pSubDyn =
  2016. (CDynasty *) pCurrentDyn->m_Children.GetAt(i);
  2017. DirectRead(
  2018. pNs,
  2019. pSubDyn,
  2020. wszTextQuery,
  2021. pParsedQuery,
  2022. pContext,
  2023. pSink,
  2024. lFlags
  2025. );
  2026. }
  2027. }
  2028. return WBEM_S_NO_ERROR;
  2029. }
  2030. // New implementation
  2031. //***************************************************************************
  2032. //
  2033. // CQueryEngine::EvaluateSubQuery
  2034. //
  2035. // Walks through a class hierarchy and executes smaller queries against
  2036. // the individual classes in the dynasty.
  2037. //
  2038. // Note that in a class hierarchy A,B:A,C:B, an enumeration/query is
  2039. // performed only against the classes in the CDynasty referenced in
  2040. // the query. For example, if "select * from B" is the query, only queries
  2041. // for B and C are performed. The CMerger logic will do individual
  2042. // 'get object' calls for any instances needed in A to complete
  2043. // the merged B/C instances while merging is taking place.
  2044. //
  2045. // Return values:
  2046. // WBEM_NO_ERROR
  2047. // WBEM_E_FAILED
  2048. //
  2049. //***************************************************************************
  2050. // error objects dealt with
  2051. HRESULT CQueryEngine::EvaluateSubQuery(
  2052. IN CWbemNamespace *pNs,
  2053. IN CDynasty *pCurrentDyn,
  2054. IN LPWSTR wszTextQuery,
  2055. IN QL_LEVEL_1_RPN_EXPRESSION *pParsedQuery,
  2056. IN IWbemContext* pContext,
  2057. IN BOOL bSuppressStaticChild,
  2058. IN CWmiMerger* pMerger, // must have combining semantics
  2059. IN CMergerSink* pSink,
  2060. IN long lFlags,
  2061. IN bool bHasRightSibling
  2062. )
  2063. {
  2064. // SJS - Amendment is the same as Abstract
  2065. if( ( pCurrentDyn->IsAbstract() || pCurrentDyn->IsAmendment() ) && (lFlags & WBEM_FLAG_SHALLOW))
  2066. {
  2067. // No instances
  2068. // ============
  2069. pSink->SetStatus( 0L, WBEM_S_NO_ERROR, 0L, NULL);
  2070. return WBEM_S_NO_ERROR;
  2071. }
  2072. // The class has its own instances if it has a key and is either dynamic
  2073. // or the first static class in the inheritance chain (otherwise these
  2074. // instances have been handled in the parent)
  2075. // =====================================================================
  2076. BOOL bHasOwnInstances = pCurrentDyn->IsKeyed() && !pCurrentDyn->IsAbstract()
  2077. && !pCurrentDyn->IsAmendment() && (pCurrentDyn->IsDynamic() || !bSuppressStaticChild);
  2078. // The class has children that we need to look at if it has children.
  2079. // ==================================================================
  2080. BOOL bHasChildren = (pCurrentDyn->m_Children.Size() > 0);
  2081. // The class hierarchy was built down from the class of the query, as
  2082. // well as up the inheritance chain, since parents may need to be used to
  2083. // build complete instances. However, parents are treated very different
  2084. // then classes derived from the class of the query (see below)
  2085. // ======================================================================
  2086. BOOL bDerivedFromTarget = (pCurrentDyn->m_pClassObj->InheritsFrom(pParsedQuery->bsClassName) == S_OK);
  2087. // Next, see if the query is executing out of a scope or the primary
  2088. // namespace. We exclude providers if the query is executing from
  2089. // a scope.
  2090. // ==================================================================
  2091. BOOL bInScope = pNs->IsSubscope();
  2092. // Now we have enough info to start getting the instances.
  2093. // =======================================================
  2094. CMergerSink* pOwnSink = NULL;
  2095. CMergerSink* pChildSink = NULL;
  2096. //
  2097. // Creates a CMergerRecord if there is not already one for the class
  2098. // Creates an InternalMerger if there are Own instances and Child classes
  2099. // returns Own and Child Sink from the MergerRecord
  2100. //
  2101. HRESULT hr = pMerger->RegisterSinkForClass( pCurrentDyn->m_wszClassName,
  2102. (_IWmiObject*) pCurrentDyn->m_pClassObj,
  2103. pContext,
  2104. bHasChildren, bHasOwnInstances,
  2105. bDerivedFromTarget,!pCurrentDyn->IsDynamic(),
  2106. pSink, &pOwnSink, &pChildSink );
  2107. CReleaseMe rm1( pOwnSink );
  2108. CReleaseMe rm2( pChildSink );
  2109. if ( FAILED(hr) )
  2110. {
  2111. pSink->SetStatus( 0L, hr, 0L, NULL );
  2112. return hr;
  2113. }
  2114. if(bHasOwnInstances)
  2115. {
  2116. if(bHasChildren)
  2117. {
  2118. // In order for the merge to succeed, we need to make sure that all
  2119. // keys are provided, whether or not we are asked for them
  2120. // ================================================================
  2121. if(!pParsedQuery->bStar)
  2122. {
  2123. CPropertyName Name;
  2124. Name.AddElement(L"__RELPATH"); // throws
  2125. pParsedQuery->AddProperty(Name);
  2126. }
  2127. // We need to figure out what to ask of the provider. If the
  2128. // provider is "downstream" from the original query, i.e. the query
  2129. // was asked against a class that is an ancestor of this one or is
  2130. // this one, we are fine --- this provider must understand the
  2131. // query. If not, we don't ask any query, just wait and then call
  2132. // GetObjectByPath.
  2133. // ================================================================
  2134. //pMerger->SetIsDerivedFromTarget(bDerivedFromTarget);
  2135. }
  2136. }
  2137. else if(!bHasChildren)
  2138. {
  2139. // No instances and no children
  2140. pSink->SetStatus( 0L, WBEM_S_NO_ERROR, 0L, NULL );
  2141. return WBEM_S_NO_ERROR;
  2142. }
  2143. // If this is an old security class, use the internal provider.
  2144. // ====================================================================
  2145. if((wbem_wcsicmp(pCurrentDyn->m_wszClassName, L"__ntlmgroup") == 0 ||
  2146. wbem_wcsicmp(pCurrentDyn->m_wszClassName, L"__ntlmuser") == 0) &&
  2147. (lFlags & WBEM_FLAG_ONLY_STATIC) == 0)
  2148. {
  2149. HRESULT hres = pNs->EnumerateSecurityClassInstances(pCurrentDyn->m_wszClassName,
  2150. pOwnSink, pContext, lFlags);
  2151. pOwnSink->SetStatus( 0L, hres, 0L, NULL );
  2152. }
  2153. // If the current subclass is the first keyed statically instanced subclass.
  2154. // =========================================================================
  2155. else if (bHasOwnInstances && !pCurrentDyn->IsDynamic())
  2156. {
  2157. // Execute the query against the static portion of the database.
  2158. // =============================================================
  2159. int nRes = 0;
  2160. if (pNs->GetNsSession()->SupportsQueries(NULL) == WBEM_S_NO_ERROR)
  2161. {
  2162. // The underlying repository automatically handles inheritance.
  2163. if (!bSuppressStaticChild)
  2164. nRes = ExecRepositoryQuery(pNs, wszTextQuery, lFlags, pContext, pSink);
  2165. if (nRes == invalid_query)
  2166. pOwnSink->SetStatus( 0L, WBEM_E_INVALID_QUERY, 0L, NULL );
  2167. else if(nRes != 0)
  2168. pOwnSink->SetStatus( 0L, WBEM_E_FAILED, 0L, NULL );
  2169. else
  2170. pOwnSink->SetStatus( 0L, WBEM_S_NO_ERROR, 0L, NULL );
  2171. }
  2172. else
  2173. {
  2174. hr = pNs->Static_QueryRepository( (CWbemObject *) pCurrentDyn->m_pClassObj,0L,
  2175. pContext, pOwnSink, pParsedQuery,
  2176. pCurrentDyn->m_wszClassName,pMerger );
  2177. }
  2178. }
  2179. else if (bHasOwnInstances && pCurrentDyn->IsDynamic() && !bInScope)
  2180. {
  2181. if (bDerivedFromTarget)
  2182. {
  2183. // Ask the provider.
  2184. // =================
  2185. ExecAtomicDynQlQuery(
  2186. pNs,
  2187. pCurrentDyn,
  2188. L"WQL",
  2189. wszTextQuery,
  2190. pParsedQuery,
  2191. lFlags, // Flags
  2192. pContext,
  2193. pOwnSink,
  2194. bHasChildren || bHasRightSibling
  2195. );
  2196. }
  2197. else
  2198. {
  2199. pOwnSink->SetStatus( 0L, WBEM_S_NO_ERROR, 0L, NULL );
  2200. }
  2201. }
  2202. // Manually release pOwnSink if appropriate - use the method on CReleaseMe() so
  2203. // as not to interfere with the auto-release functionality. We should do
  2204. // this here so as to relinquish any unnecessary locks we may be holding on data
  2205. // and/or results before we start spinning off child requests - it's all about
  2206. // throughput boyo!
  2207. if(pOwnSink)
  2208. rm1.release();
  2209. // If the current subclass is the first keyed statically instanced subclass.
  2210. // =========================================================================
  2211. if (bHasOwnInstances && !pCurrentDyn->IsDynamic())
  2212. {
  2213. bSuppressStaticChild = TRUE;
  2214. }
  2215. // Evaluate child classes.
  2216. // =======================
  2217. if (bHasChildren)
  2218. {
  2219. for (int i = 0; i < pCurrentDyn->m_Children.Size(); i++)
  2220. {
  2221. CDynasty *pSubDyn = (CDynasty *) pCurrentDyn->m_Children.GetAt(i);
  2222. EvaluateSubQuery (
  2223. pNs,
  2224. pSubDyn,
  2225. wszTextQuery,
  2226. pParsedQuery,
  2227. pContext,
  2228. bSuppressStaticChild,
  2229. pMerger,
  2230. pChildSink,
  2231. lFlags,
  2232. bHasRightSibling || ( ( i != ( pCurrentDyn->m_Children.Size () - 1 )) ? true : false )
  2233. ) ;
  2234. }
  2235. }
  2236. return WBEM_S_NO_ERROR;
  2237. }
  2238. // Old implementation
  2239. //***************************************************************************
  2240. //
  2241. // CQueryEngine::EvaluateSubQuery
  2242. //
  2243. // Walks through a class hierarchy and executes smaller queries against
  2244. // the individual classes in the dynasty.
  2245. //
  2246. // Note that in a class hierarchy A,B:A,C:B, an enumeration/query is
  2247. // performed only against the classes in the CDynasty referenced in
  2248. // the query. For example, if "select * from B" is the query, only queries
  2249. // for B and C are performed. The CMerger logic will do individual
  2250. // 'get object' calls for any instances needed in A to complete
  2251. // the merged B/C instances while merging is taking place.
  2252. //
  2253. // Return values:
  2254. // WBEM_NO_ERROR
  2255. // WBEM_E_FAILED
  2256. //
  2257. //***************************************************************************
  2258. // error objects dealt with
  2259. HRESULT CQueryEngine::EvaluateSubQuery_old(
  2260. IN CWbemNamespace *pNs,
  2261. IN CDynasty *pCurrentDyn,
  2262. IN LPWSTR wszTextQuery,
  2263. IN QL_LEVEL_1_RPN_EXPRESSION *pParsedQuery,
  2264. IN IWbemContext* pContext,
  2265. IN BOOL bSuppressStaticChild,
  2266. IN CBasicObjectSink* pSink, // must have combining semantics
  2267. IN long lFlags,
  2268. IN bool bHasRightSibling
  2269. )
  2270. {
  2271. // SJS - Amendment is the same as Abstract
  2272. if( ( pCurrentDyn->IsAbstract() || pCurrentDyn->IsAmendment() ) && (lFlags & WBEM_FLAG_SHALLOW))
  2273. {
  2274. // No instances
  2275. // ============
  2276. return pSink->Return(WBEM_S_NO_ERROR);
  2277. }
  2278. // The class has its own instances if it has a key and is either dynamic
  2279. // or the first static class in the inheritance chain (otherwise these
  2280. // instances have been handled in the parent)
  2281. // =====================================================================
  2282. BOOL bHasOwnInstances = pCurrentDyn->IsKeyed() && !pCurrentDyn->IsAbstract()
  2283. && !pCurrentDyn->IsAmendment() && (pCurrentDyn->IsDynamic() || !bSuppressStaticChild);
  2284. // The class has children that we need to look at if it has children.
  2285. // ==================================================================
  2286. BOOL bHasChildren = (pCurrentDyn->m_Children.Size() > 0);
  2287. // The class hierarchy was built down from the class of the query, as
  2288. // well as up the inheritance chain, since parents may need to be used to
  2289. // build complete instances. However, parents are treated very different
  2290. // then classes derived from the class of the query (see below)
  2291. // ======================================================================
  2292. BOOL bDerivedFromTarget = (pCurrentDyn->m_pClassObj->InheritsFrom(
  2293. pParsedQuery->bsClassName) == S_OK);
  2294. // Next, see if the query is executing out of a scope or the primary
  2295. // namespace. We exclude providers if the query is executing from
  2296. // a scope.
  2297. // ==================================================================
  2298. BOOL bInScope = pNs->IsSubscope();
  2299. // Now we have enough info to start getting the instances.
  2300. // =======================================================
  2301. CBasicObjectSink* pChildSink = NULL;
  2302. CBasicObjectSink* pOwnSink = NULL;
  2303. if(bHasOwnInstances)
  2304. {
  2305. if(bHasChildren)
  2306. {
  2307. // Has instances and children have instances
  2308. // =========================================
  2309. CMerger* pMerger = new CMerger(pSink,
  2310. (CWbemClass*)pCurrentDyn->m_pClassObj, pNs, pContext);
  2311. if (pMerger && pMerger->IsValid())
  2312. {
  2313. pOwnSink = pMerger->GetOwnSink();
  2314. pOwnSink->AddRef();
  2315. pChildSink = pMerger->GetChildSink();
  2316. pChildSink->AddRef();
  2317. // In order for the merge to succeed, we need to make sure that all
  2318. // keys are provided, whether or not we are asked for them
  2319. // ================================================================
  2320. if(!pParsedQuery->bStar)
  2321. {
  2322. CPropertyName Name;
  2323. Name.AddElement(L"__RELPATH");
  2324. pParsedQuery->AddProperty(Name);
  2325. }
  2326. // We need to figure out what to ask of the provider. If the
  2327. // provider is "downstream" from the original query, i.e. the query
  2328. // was asked against a class that is an ancestor of this one or is
  2329. // this one, we are fine --- this provider must understand the
  2330. // query. If not, we don't ask any query, just wait and then call
  2331. // GetObjectByPath.
  2332. // ================================================================
  2333. pMerger->SetIsDerivedFromTarget(bDerivedFromTarget);
  2334. }
  2335. else
  2336. {
  2337. return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  2338. }
  2339. }
  2340. else
  2341. {
  2342. // No children --- own instances are it
  2343. // ====================================
  2344. pOwnSink = pSink;
  2345. pSink->AddRef();
  2346. }
  2347. }
  2348. else if(bHasChildren)
  2349. {
  2350. // Our children are it
  2351. // ===================
  2352. pChildSink = pSink;
  2353. pSink->AddRef();
  2354. }
  2355. else
  2356. {
  2357. // No instances
  2358. // ============
  2359. return pSink->Return(WBEM_S_NO_ERROR);
  2360. }
  2361. // If this is an old security class, use the internal provider.
  2362. // ====================================================================
  2363. if((wbem_wcsicmp(pCurrentDyn->m_wszClassName, L"__ntlmgroup") == 0 ||
  2364. wbem_wcsicmp(pCurrentDyn->m_wszClassName, L"__ntlmuser") == 0) &&
  2365. (lFlags & WBEM_FLAG_ONLY_STATIC) == 0)
  2366. {
  2367. HRESULT hres = pNs->EnumerateSecurityClassInstances(pCurrentDyn->m_wszClassName,
  2368. pOwnSink, pContext, lFlags);
  2369. pOwnSink->Return(hres);
  2370. }
  2371. // If the current subclass is the first keyed statically instanced subclass.
  2372. // =========================================================================
  2373. else if (bHasOwnInstances && !pCurrentDyn->IsDynamic())
  2374. {
  2375. // Execute the query against the static portion of the database.
  2376. // =============================================================
  2377. int nRes = 0;
  2378. if (pNs->GetNsSession()->SupportsQueries(NULL) == WBEM_S_NO_ERROR)
  2379. {
  2380. // The underlying repository automatically handles inheritance.
  2381. if (!bSuppressStaticChild)
  2382. nRes = ExecRepositoryQuery(pNs, wszTextQuery, lFlags, pContext, pSink);
  2383. }
  2384. else
  2385. {
  2386. nRes = ExecAtomicDbQuery(pNs->GetNsSession(), pNs->GetNsHandle(), pNs->GetScope(), pCurrentDyn->m_wszClassName,
  2387. pParsedQuery, pOwnSink, pNs);
  2388. }
  2389. if (nRes == invalid_query)
  2390. pOwnSink->Return(WBEM_E_INVALID_QUERY);
  2391. else if(nRes != 0)
  2392. pOwnSink->Return(WBEM_E_FAILED);
  2393. else
  2394. pOwnSink->Return(WBEM_S_NO_ERROR);
  2395. }
  2396. else if (bHasOwnInstances && pCurrentDyn->IsDynamic() && !bInScope)
  2397. {
  2398. if (bDerivedFromTarget)
  2399. {
  2400. // Ask the provider.
  2401. // =================
  2402. ExecAtomicDynQlQuery(
  2403. pNs,
  2404. pCurrentDyn,
  2405. L"WQL",
  2406. wszTextQuery,
  2407. pParsedQuery,
  2408. lFlags, // Flags
  2409. pContext,
  2410. pOwnSink,
  2411. bHasChildren || bHasRightSibling
  2412. );
  2413. }
  2414. else
  2415. {
  2416. pOwnSink->Return(WBEM_S_NO_ERROR);
  2417. }
  2418. }
  2419. if(pOwnSink)
  2420. pOwnSink->Release();
  2421. // If the current subclass is the first keyed statically instanced subclass.
  2422. // =========================================================================
  2423. if (bHasOwnInstances && !pCurrentDyn->IsDynamic())
  2424. {
  2425. bSuppressStaticChild = TRUE;
  2426. }
  2427. // Evaluate child classes.
  2428. // =======================
  2429. if (bHasChildren)
  2430. {
  2431. for (int i = 0; i < pCurrentDyn->m_Children.Size(); i++)
  2432. {
  2433. CDynasty *pSubDyn = (CDynasty *) pCurrentDyn->m_Children.GetAt(i);
  2434. EvaluateSubQuery_old(
  2435. pNs,
  2436. pSubDyn,
  2437. wszTextQuery,
  2438. pParsedQuery,
  2439. pContext,
  2440. bSuppressStaticChild,
  2441. pChildSink,
  2442. lFlags,
  2443. bHasRightSibling || ( ( i != ( pCurrentDyn->m_Children.Size () - 1 )) ? true : false )
  2444. ) ;
  2445. }
  2446. }
  2447. if(pChildSink)
  2448. pChildSink->Release();
  2449. return WBEM_S_NO_ERROR;
  2450. }
  2451. //***************************************************************************
  2452. //
  2453. //***************************************************************************
  2454. HRESULT CQueryEngine::EliminateDerivedProperties(
  2455. IN QL_LEVEL_1_RPN_EXPRESSION* pOrigQuery,
  2456. IN CWbemClass* pClass,
  2457. IN BOOL bRelax,
  2458. OUT QL_LEVEL_1_RPN_EXPRESSION** ppNewQuery)
  2459. {
  2460. HRESULT hres = WBEM_S_NO_ERROR;
  2461. // Set up the new query to talk about this class
  2462. // =============================================
  2463. CVar vClassName;
  2464. hres = pClass->GetClassName(&vClassName);
  2465. if (FAILED(hres))
  2466. return hres;
  2467. (*ppNewQuery)->bsClassName = SysAllocString(vClassName.GetLPWSTR());
  2468. if (0==(*ppNewQuery)->bsClassName)
  2469. return WBEM_E_OUT_OF_MEMORY;
  2470. if(pOrigQuery->nNumTokens == 0)
  2471. {
  2472. *ppNewQuery = new QL_LEVEL_1_RPN_EXPRESSION;
  2473. if (*ppNewQuery)
  2474. return WBEM_S_NO_ERROR;
  2475. else
  2476. return WBEM_E_OUT_OF_MEMORY;
  2477. }
  2478. // Set up a stack of expressions
  2479. // =============================
  2480. std::stack<QL_LEVEL_1_RPN_EXPRESSION*, deque <QL_LEVEL_1_RPN_EXPRESSION*, wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
  2481. // Recursively "evaluate" the original query
  2482. // =========================================
  2483. for(int i = 0; i < pOrigQuery->nNumTokens; i++)
  2484. {
  2485. QL_LEVEL_1_TOKEN& Token = pOrigQuery->pArrayOfTokens[i];
  2486. QL_LEVEL_1_RPN_EXPRESSION* pNew = NULL;
  2487. QL_LEVEL_1_RPN_EXPRESSION* pFirst = NULL;
  2488. QL_LEVEL_1_RPN_EXPRESSION* pSecond = NULL;
  2489. switch(Token.nTokenType)
  2490. {
  2491. case QL1_OP_EXPRESSION:
  2492. if(IsTokenAboutClass(Token, pClass))
  2493. {
  2494. QL_LEVEL_1_RPN_EXPRESSION* pNew = new QL_LEVEL_1_RPN_EXPRESSION;
  2495. if (pNew)
  2496. pNew->AddToken(Token);
  2497. else
  2498. {
  2499. // force exit
  2500. i = pOrigQuery->nNumTokens;
  2501. }
  2502. }
  2503. else
  2504. {
  2505. if(bRelax)
  2506. {
  2507. QL_LEVEL_1_RPN_EXPRESSION* pNew =
  2508. new QL_LEVEL_1_RPN_EXPRESSION;
  2509. if (pNew)
  2510. ExprStack.push(pNew);
  2511. else
  2512. {
  2513. // force exit
  2514. i = pOrigQuery->nNumTokens;
  2515. }
  2516. }
  2517. else
  2518. {
  2519. ExprStack.push(NULL);
  2520. }
  2521. }
  2522. break;
  2523. case QL1_AND:
  2524. if(ExprStack.size() < 2)
  2525. {
  2526. hres = WBEM_E_CRITICAL_ERROR;
  2527. break;
  2528. }
  2529. pFirst = ExprStack.top(); ExprStack.pop();
  2530. pSecond = ExprStack.top(); ExprStack.pop();
  2531. hres = AndQueryExpressions(pFirst, pSecond, &pNew);
  2532. ExprStack.push(pNew);
  2533. delete pFirst;
  2534. delete pSecond;
  2535. break;
  2536. case QL1_OR:
  2537. if(ExprStack.size() < 2)
  2538. {
  2539. hres = WBEM_E_CRITICAL_ERROR;
  2540. break;
  2541. }
  2542. pFirst = ExprStack.top(); ExprStack.pop();
  2543. pSecond = ExprStack.top(); ExprStack.pop();
  2544. hres = OrQueryExpressions(pFirst, pSecond, &pNew);
  2545. ExprStack.push(pNew);
  2546. delete pFirst;
  2547. delete pSecond;
  2548. break;
  2549. case QL1_NOT:
  2550. if(ExprStack.size() < 1)
  2551. {
  2552. hres = WBEM_E_CRITICAL_ERROR;
  2553. break;
  2554. }
  2555. pFirst = ExprStack.top(); ExprStack.pop();
  2556. if(bRelax)
  2557. {
  2558. QL_LEVEL_1_RPN_EXPRESSION* pNew = new QL_LEVEL_1_RPN_EXPRESSION;
  2559. if (pNew)
  2560. ExprStack.push(pNew);
  2561. else
  2562. {
  2563. // force exit
  2564. i = pOrigQuery->nNumTokens;
  2565. }
  2566. }
  2567. else
  2568. {
  2569. ExprStack.push(NULL);
  2570. }
  2571. delete pFirst;
  2572. break;
  2573. default:
  2574. hres = WBEM_E_CRITICAL_ERROR;
  2575. delete pNew;
  2576. }
  2577. if(FAILED(hres))
  2578. {
  2579. // An error occurred, break out of the loop
  2580. // ========================================
  2581. break;
  2582. }
  2583. }
  2584. if(SUCCEEDED(hres) && ExprStack.size() != 1)
  2585. {
  2586. hres = WBEM_E_CRITICAL_ERROR;
  2587. }
  2588. if(FAILED(hres))
  2589. {
  2590. // An error occurred. Clear the stack
  2591. // ==================================
  2592. while(!ExprStack.empty())
  2593. {
  2594. delete ExprStack.top();
  2595. ExprStack.pop();
  2596. }
  2597. return hres;
  2598. }
  2599. // All is good
  2600. // ===========
  2601. *ppNewQuery = ExprStack.top();
  2602. return S_OK;
  2603. }
  2604. //***************************************************************************
  2605. //
  2606. //***************************************************************************
  2607. BOOL CQueryEngine::IsTokenAboutClass(IN QL_LEVEL_1_TOKEN& Token,
  2608. IN CWbemClass* pClass)
  2609. {
  2610. CPropertyName& TokenPropName = Token.PropertyName;
  2611. if(TokenPropName.GetNumElements() != 1)
  2612. return FALSE;
  2613. LPWSTR wszPropName = (LPWSTR)TokenPropName.GetStringAt(0);
  2614. return SUCCEEDED(pClass->GetPropertyType(wszPropName, NULL, NULL));
  2615. }
  2616. //***************************************************************************
  2617. //
  2618. //***************************************************************************
  2619. HRESULT CQueryEngine::AndQueryExpressions(
  2620. IN QL_LEVEL_1_RPN_EXPRESSION* pFirst,
  2621. IN QL_LEVEL_1_RPN_EXPRESSION* pSecond,
  2622. OUT QL_LEVEL_1_RPN_EXPRESSION** ppNew)
  2623. {
  2624. // If either one is false, the result is false
  2625. // ===========================================
  2626. if(pFirst == NULL || pSecond == NULL)
  2627. {
  2628. *ppNew = NULL;
  2629. return WBEM_S_NO_ERROR;
  2630. }
  2631. *ppNew = new QL_LEVEL_1_RPN_EXPRESSION;
  2632. if (NULL == *ppNew)
  2633. {
  2634. return WBEM_E_OUT_OF_MEMORY;
  2635. }
  2636. // If either one is empty, take the other
  2637. // ======================================
  2638. if(pFirst->nNumTokens == 0)
  2639. {
  2640. AppendQueryExpression(*ppNew, pSecond);
  2641. return WBEM_S_NO_ERROR;
  2642. }
  2643. if(pSecond->nNumTokens == 0)
  2644. {
  2645. AppendQueryExpression(*ppNew, pFirst);
  2646. return WBEM_S_NO_ERROR;
  2647. }
  2648. // Both are there --- and together
  2649. // ===============================
  2650. AppendQueryExpression(*ppNew, pFirst);
  2651. AppendQueryExpression(*ppNew, pSecond);
  2652. QL_LEVEL_1_TOKEN Token;
  2653. Token.nTokenType = QL1_AND;
  2654. (*ppNew)->AddToken(Token);
  2655. return WBEM_S_NO_ERROR;
  2656. }
  2657. //***************************************************************************
  2658. //
  2659. //***************************************************************************
  2660. HRESULT CQueryEngine::OrQueryExpressions(
  2661. IN QL_LEVEL_1_RPN_EXPRESSION* pFirst,
  2662. IN QL_LEVEL_1_RPN_EXPRESSION* pSecond,
  2663. OUT QL_LEVEL_1_RPN_EXPRESSION** ppNew)
  2664. {
  2665. // If both are false, so is the resulkt
  2666. // ====================================
  2667. if(pFirst == NULL && pSecond == NULL)
  2668. {
  2669. *ppNew = NULL;
  2670. return WBEM_S_NO_ERROR;
  2671. }
  2672. *ppNew = new QL_LEVEL_1_RPN_EXPRESSION;
  2673. if (NULL == *ppNew)
  2674. {
  2675. return WBEM_E_OUT_OF_MEMORY;
  2676. }
  2677. // If either one is empty, so is the result
  2678. // ========================================
  2679. if(pFirst->nNumTokens == 0 || pSecond->nNumTokens == 0)
  2680. {
  2681. return WBEM_S_NO_ERROR;
  2682. }
  2683. // If either one is false, return the other
  2684. // ========================================
  2685. if(pFirst == NULL)
  2686. {
  2687. AppendQueryExpression(*ppNew, pSecond);
  2688. return WBEM_S_NO_ERROR;
  2689. }
  2690. if(pSecond == NULL)
  2691. {
  2692. AppendQueryExpression(*ppNew, pFirst);
  2693. return WBEM_S_NO_ERROR;
  2694. }
  2695. // Both are there --- or together
  2696. // ==============================
  2697. AppendQueryExpression(*ppNew, pFirst);
  2698. AppendQueryExpression(*ppNew, pSecond);
  2699. QL_LEVEL_1_TOKEN Token;
  2700. Token.nTokenType = QL1_OR;
  2701. (*ppNew)->AddToken(Token);
  2702. return WBEM_S_NO_ERROR;
  2703. }
  2704. //***************************************************************************
  2705. //
  2706. //***************************************************************************
  2707. void CQueryEngine::AppendQueryExpression(
  2708. IN QL_LEVEL_1_RPN_EXPRESSION* pDest,
  2709. IN QL_LEVEL_1_RPN_EXPRESSION* pSource)
  2710. {
  2711. for(int i = 0; i < pSource->nNumTokens; i++)
  2712. {
  2713. pDest->AddToken(pSource->pArrayOfTokens[i]);
  2714. }
  2715. }
  2716. //***************************************************************************
  2717. //
  2718. //***************************************************************************
  2719. BSTR CQueryEngine::GetParentPath(CWbemInstance* pInst, LPCWSTR wszClassName)
  2720. {
  2721. // Get the relative path of the instance
  2722. // =====================================
  2723. LPWSTR wszRelPath = pInst->GetRelPath();
  2724. if(wszRelPath == NULL)
  2725. return NULL;
  2726. BSTR str = AdjustPathToClass(wszRelPath, wszClassName);
  2727. delete [] wszRelPath;
  2728. return str;
  2729. }
  2730. //***************************************************************************
  2731. //
  2732. //***************************************************************************
  2733. BSTR CQueryEngine::AdjustPathToClass(LPCWSTR wszRelPath, LPCWSTR wszClassName)
  2734. {
  2735. // Skip the absolute path
  2736. // ======================
  2737. if(wszRelPath[0] == '\\')
  2738. {
  2739. wszRelPath = wcschr(wszRelPath, ':');
  2740. if(wszRelPath == NULL)
  2741. return NULL;
  2742. else
  2743. wszRelPath++;
  2744. }
  2745. // Find the "post-classname" part
  2746. // ==============================
  2747. WCHAR* pwcDot = wcschr(wszRelPath, L'.');
  2748. WCHAR* pwcEquals = wcschr(wszRelPath, L'=');
  2749. LPWSTR wszPostClassPart;
  2750. if(pwcDot == NULL)
  2751. wszPostClassPart = pwcEquals;
  2752. else if(pwcEquals == NULL)
  2753. wszPostClassPart = pwcDot;
  2754. else if(pwcDot < pwcEquals)
  2755. wszPostClassPart = pwcDot;
  2756. else
  2757. wszPostClassPart = pwcEquals;
  2758. // Allocate the BSTR for the real thing
  2759. // ====================================
  2760. BSTR strNewPath;
  2761. if(wszPostClassPart)
  2762. {
  2763. size_t tmpLength = wcslen(wszClassName) + wcslen(wszPostClassPart); // SEC:REVIEWED 2002-03-22 : OK, prior logic assures NULLs
  2764. strNewPath = SysAllocStringLen(NULL, tmpLength); // SEC:REVIEWED 2002-03-22 : OK, prior logic assures proper size
  2765. if (strNewPath)
  2766. StringCchPrintfW(strNewPath, tmpLength+1, L"%s%s", wszClassName, wszPostClassPart);
  2767. }
  2768. else
  2769. {
  2770. strNewPath = SysAllocString(wszClassName);
  2771. }
  2772. return strNewPath;
  2773. }
  2774. //***************************************************************************
  2775. //
  2776. // CQueryEngine::ExecAtomicDbQuery
  2777. //
  2778. // General purpose query driver for QL LEVEL 1. This method parses
  2779. // and executes the query against the database engine. The optimizer
  2780. // is contained within this function and its auxiliaries.
  2781. //
  2782. // Preconditions:
  2783. // (1) All classes involved in the query are known to have
  2784. // only static instances in the database. No interface to dynamic
  2785. // classes is provided.
  2786. // (2) This method cannot resolve queries against abstract base classes.
  2787. //
  2788. // Parameters:
  2789. // <dwNs> The target namespace.
  2790. // <pQueryText> The QL1 query, unparsed.
  2791. // <pEnum> Receives the enumerator containing the result set.
  2792. //
  2793. // Return values:
  2794. // <no_error>
  2795. // <invalid_query>
  2796. // <failed>
  2797. // <out_of_memory>
  2798. //
  2799. //***************************************************************************
  2800. // ok / no error objects required
  2801. int CQueryEngine::ExecAtomicDbQuery(
  2802. IN IWmiDbSession *pSession,
  2803. IN IWmiDbHandle *pNsHandle,
  2804. IN IWmiDbHandle *pScopeHandle,
  2805. IN LPCWSTR wszClassName,
  2806. IN QL_LEVEL_1_RPN_EXPRESSION *pExp,
  2807. IN CBasicObjectSink* pDest, // no status
  2808. IN CWbemNamespace * pNs)
  2809. {
  2810. int nRetVal = 0;
  2811. int nRes;
  2812. // Examine the query and see if we can execute it
  2813. // in any kind of optimized fashion.
  2814. // ==============================================
  2815. CWbemObject *pClassDef = 0;
  2816. LPWSTR pPropToUse = 0;
  2817. CVar *pValToUse = 0;
  2818. int nType = 0;
  2819. nRes = QueryOptimizationTest(
  2820. pSession,
  2821. pNsHandle,
  2822. pScopeHandle,
  2823. wszClassName,
  2824. pExp,
  2825. &pClassDef,
  2826. &pPropToUse,
  2827. &pValToUse,
  2828. &nType
  2829. );
  2830. if (nRes == use_key)
  2831. {
  2832. nRes = KeyedQuery(
  2833. pSession,
  2834. pNsHandle,
  2835. pExp,
  2836. pClassDef,
  2837. 0,
  2838. pDest,
  2839. pNs
  2840. );
  2841. if (nRes != 0)
  2842. nRetVal = failed;
  2843. }
  2844. else if (nRes == use_table_scan || nRes == use_index)
  2845. {
  2846. HRESULT hRes = CRepository::TableScanQuery(
  2847. pSession,
  2848. pScopeHandle,
  2849. (LPWSTR)wszClassName,
  2850. pExp,
  2851. 0,
  2852. pDest
  2853. );
  2854. if (FAILED(hRes))
  2855. nRetVal = failed;
  2856. else
  2857. nRetVal = 0;
  2858. }
  2859. delete pValToUse;
  2860. delete pPropToUse;
  2861. if (pClassDef)
  2862. pClassDef->Release();
  2863. return nRetVal;
  2864. }
  2865. //***************************************************************************
  2866. //
  2867. // CQueryEngine::QueryOptimizationTest
  2868. //
  2869. // Examines a query and its associated class definition. It determines
  2870. // what optimizations, if any, can be applied to speed up the query.
  2871. // If the query is conjunctive and there is some form of primary or
  2872. // secondary indexing which can be used, this method selects the
  2873. // appropriate property to use for a retrieval by key or an indexed query.
  2874. // If <table_scan> is returned, then a table scan is required.
  2875. //
  2876. // Parameters:
  2877. // <dwNs> The relevant namespace.
  2878. // <pExp> A valid QL1 expression.
  2879. // <pClassDef> Always receives the deserialized class definition, as long
  2880. // as <invalid_class> is not returned. Use operator
  2881. // delete to deallocate.
  2882. //
  2883. // <pPropToUse> If <use_index> is returned, this is assigned to point
  2884. // to an indexed property. Use operator delete to deallocate
  2885. // This always refers to a non-key property name.
  2886. // Set to NULL if <table_scan> is returned.
  2887. //
  2888. // <pValToUse> The value to use if <use_index> is returned.
  2889. // Set to NULL if <use_index> is not returned.
  2890. //
  2891. // <pnType> Receives the VT_ type of the relevant property.
  2892. // Set to NULL if <use_index> is not returned.
  2893. //
  2894. // Return values:
  2895. // <invalid_class> The class did not appear to exist.
  2896. // <use_index> The value returned via <pPropToUse> is a property
  2897. // with a secondary index which can beused to limit
  2898. // the query.
  2899. // <use_key> The query is such that all of the key properties
  2900. // were specified with equality tests.
  2901. // <use_table_scan> A table scan is required.
  2902. //
  2903. //***************************************************************************
  2904. // ok
  2905. int CQueryEngine::QueryOptimizationTest(
  2906. IN IWmiDbSession *pSession,
  2907. IN IWmiDbHandle *pNsHandle,
  2908. IN IWmiDbHandle *pScopeHandle,
  2909. IN LPCWSTR wszClassName,
  2910. IN QL_LEVEL_1_RPN_EXPRESSION *pExp,
  2911. OUT CWbemObject **pClassDef,
  2912. OUT LPWSTR *pPropToUse,
  2913. OUT CVar **pValToUse,
  2914. OUT int *pnType
  2915. )
  2916. {
  2917. int nRes;
  2918. if (pNsHandle == 0 || pExp == 0 || pClassDef == 0 || pPropToUse == 0 ||
  2919. pValToUse == 0 || pnType == 0)
  2920. return invalid_parameter;
  2921. // Defaults.
  2922. // =========
  2923. *pClassDef = 0;
  2924. *pPropToUse = 0;
  2925. *pValToUse = 0;
  2926. *pnType = 0;
  2927. // Look up the class definition.
  2928. // =============================
  2929. IWbemClassObject *pCls = 0;
  2930. HRESULT hRes = CRepository::GetObject(pSession, pNsHandle, wszClassName, 0, &pCls);
  2931. if (FAILED(hRes))
  2932. return invalid_class;
  2933. CWbemClass *pClsDef = (CWbemClass *) pCls;
  2934. *pClassDef = pClsDef;
  2935. // Test query for conjunctiveness.
  2936. // ===============================
  2937. if (!IsConjunctiveQuery(pExp))
  2938. return use_table_scan;
  2939. // If here, the query is conjunctive. However, a table scan
  2940. // may still be required if the only relational tests are on
  2941. // non-indexed or non-keyed properties.
  2942. // First, get the key properties. If all of the keys
  2943. // are used with equality tests, then we could simply retrieve
  2944. // the object by key and test it.
  2945. // ===========================================================
  2946. CWStringArray aKeyProps;
  2947. pClsDef->GetKeyProps(aKeyProps);
  2948. if (QueryKeyTest(pExp, pClsDef, aKeyProps))
  2949. {
  2950. return use_key;
  2951. }
  2952. // If here, the keys were not adequate for limiting
  2953. // the query. We next try to see if any indexed properties
  2954. // were used.
  2955. // =======================================================
  2956. CWStringArray aIndexedProps;
  2957. pClsDef->GetIndexedProps(aIndexedProps);
  2958. if (QueryIndexTest(pExp, pClsDef, aIndexedProps, pPropToUse,
  2959. pValToUse, pnType))
  2960. {
  2961. if (*pValToUse == 0)
  2962. return use_table_scan;
  2963. // Try to coerce
  2964. // =============
  2965. if ((*pValToUse)->ChangeTypeTo(CType::GetVARTYPE(*pnType)))
  2966. {
  2967. return use_index;
  2968. }
  2969. return use_table_scan;
  2970. }
  2971. // If here, we have to use a table scan after all.
  2972. // ===============================================
  2973. return use_table_scan;
  2974. }
  2975. //***************************************************************************
  2976. //
  2977. // CQueryEngine::IsConjunctiveQuery
  2978. //
  2979. // Does an initial screen of a query to see if it clearly not optimizable.
  2980. //
  2981. // If the query contains an OR or NOT operator, it cannot currently be
  2982. // optimized.
  2983. //
  2984. //***************************************************************************
  2985. // ok
  2986. BOOL CQueryEngine::IsConjunctiveQuery(
  2987. IN QL_LEVEL_1_RPN_EXPRESSION *pExp
  2988. )
  2989. {
  2990. for (int i2 = 0; i2 < pExp->nNumTokens; i2++)
  2991. {
  2992. QL_LEVEL_1_TOKEN& Tok = pExp->pArrayOfTokens[i2];
  2993. if (Tok.nTokenType == QL_LEVEL_1_TOKEN::TOKEN_OR ||
  2994. Tok.nTokenType == QL_LEVEL_1_TOKEN::TOKEN_NOT
  2995. )
  2996. return FALSE;
  2997. }
  2998. return TRUE;
  2999. }
  3000. //***************************************************************************
  3001. //
  3002. // CQueryEngine::QueryKeyTest
  3003. //
  3004. // Examines a query to see if the result set must be a single instance
  3005. // due to use of the key in the 'where' clause. Not only must the
  3006. // key(s) be tested for equality, there must be only a single token or
  3007. // else all operators must be AND operators.
  3008. //
  3009. // This also performs type checking on the key(s).
  3010. //
  3011. //***************************************************************************
  3012. // ok
  3013. BOOL CQueryEngine::QueryKeyTest(
  3014. IN QL_LEVEL_1_RPN_EXPRESSION *pExp,
  3015. IN CWbemObject *pClassDef,
  3016. IN CWStringArray &aKeyProps
  3017. )
  3018. {
  3019. if (aKeyProps.Size() == 0)
  3020. return FALSE;
  3021. for (int i = 0; i < aKeyProps.Size(); i++)
  3022. {
  3023. // Check for unsupported key types
  3024. // ===============================
  3025. CIMTYPE ct;
  3026. pClassDef->GetPropertyType(aKeyProps[i], &ct);
  3027. if(ct == CIM_CHAR16 || ct == CIM_REFERENCE || ct== CIM_DATETIME)
  3028. return FALSE;
  3029. BOOL bFound = FALSE;
  3030. for (int i2 = 0; i2 < pExp->nNumTokens; i2++)
  3031. {
  3032. QL_LEVEL_1_TOKEN& Tok = pExp->pArrayOfTokens[i2];
  3033. if (Tok.nTokenType == QL_LEVEL_1_TOKEN::OP_EXPRESSION)
  3034. {
  3035. // If there is a matching property, check the rest
  3036. // of the expression to ensure type compatibility
  3037. // and that an equality test is used.
  3038. // ===============================================
  3039. LPWSTR wszPropName = GetSimplePropertyName(Tok.PropertyName);
  3040. if (wszPropName && wbem_wcsicmp(wszPropName, aKeyProps[i]) == 0)
  3041. {
  3042. if (Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL)
  3043. {
  3044. // TBD: Do a type check test here.
  3045. if(bFound)
  3046. return FALSE; // Duplicate, probably not a good query for keys!
  3047. bFound = TRUE;
  3048. }
  3049. else
  3050. {
  3051. return FALSE; // The key is being used in a non-equality comparison!! (Bug #43969)
  3052. }
  3053. }
  3054. }
  3055. }
  3056. if (!bFound)
  3057. return FALSE;
  3058. }
  3059. return TRUE;
  3060. }
  3061. //***************************************************************************
  3062. //
  3063. // CQueryEngine::QueryIndexTest
  3064. //
  3065. // Examines a query to see if the result set can be limited by use
  3066. // of a secondary index.
  3067. //
  3068. //***************************************************************************
  3069. // ok
  3070. BOOL CQueryEngine::QueryIndexTest(
  3071. IN QL_LEVEL_1_RPN_EXPRESSION *pExp,
  3072. IN CWbemObject *pClsDef,
  3073. IN CWStringArray &aIndexedProps,
  3074. OUT LPWSTR *pPropToUse,
  3075. OUT CVar **pValToUse,
  3076. OUT int *pnType
  3077. )
  3078. {
  3079. for (int i = 0; i < pExp->nNumTokens; i++)
  3080. {
  3081. QL_LEVEL_1_TOKEN& Tok = pExp->pArrayOfTokens[i];
  3082. if (Tok.nTokenType == QL_LEVEL_1_TOKEN::OP_EXPRESSION &&
  3083. Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL)
  3084. {
  3085. for (int i2 = 0; i2 < aIndexedProps.Size(); i2++)
  3086. {
  3087. LPWSTR wszPropName = GetSimplePropertyName(Tok.PropertyName);
  3088. if (wszPropName &&
  3089. wbem_wcsicmp(wszPropName, aIndexedProps[i2]) == 0)
  3090. {
  3091. CIMTYPE ctType;
  3092. HRESULT hRes = pClsDef->GetPropertyType(aIndexedProps[i2],
  3093. &ctType);
  3094. if ((ctType != CIM_SINT8) &&
  3095. (ctType != CIM_UINT8) &&
  3096. (ctType != CIM_SINT16) &&
  3097. (ctType != CIM_UINT16) &&
  3098. (ctType != CIM_SINT32) &&
  3099. (ctType != CIM_UINT32) &&
  3100. (ctType != CIM_CHAR16) &&
  3101. (ctType != CIM_STRING))
  3102. continue;
  3103. // If here, we have a match.
  3104. // =========================
  3105. *pPropToUse = Macro_CloneLPWSTR(aIndexedProps[i2]);
  3106. *pValToUse = new CVar(&Tok.vConstValue);
  3107. // a-levn: added support for NULLs
  3108. *pnType = (int)ctType;
  3109. return TRUE;
  3110. }
  3111. }
  3112. }
  3113. }
  3114. return FALSE;
  3115. }
  3116. //***************************************************************************
  3117. //
  3118. //***************************************************************************
  3119. BOOL AreWeLocal(WCHAR * pServerMachine)
  3120. {
  3121. if(pServerMachine == NULL)
  3122. return TRUE;
  3123. if(0 == wbem_wcsicmp(pServerMachine,L"."))
  3124. return TRUE;
  3125. BOOL bRet = (0 == wbem_wcsicmp(ConfigMgr::GetMachineName(),pServerMachine));
  3126. return bRet;
  3127. }
  3128. LPWSTR CQueryEngine::NormalizePath(LPCWSTR wszObjectPath, CWbemNamespace * pNs)
  3129. {
  3130. CObjectPathParser Parser;
  3131. ParsedObjectPath* pParsedPath;
  3132. LPWSTR pReturnString = NULL;
  3133. if(CObjectPathParser::NoError != Parser.Parse((LPWSTR)wszObjectPath, &pParsedPath)) return NULL;
  3134. OnDeleteObj<ParsedObjectPath*,CObjectPathParser,
  3135. void (CObjectPathParser:: *)(ParsedObjectPath *pOutput),
  3136. &CObjectPathParser::Free> FreeMe(&Parser,pParsedPath);
  3137. if (!pParsedPath->IsObject()) return NULL;
  3138. if(NULL == pParsedPath->m_pClass) return NULL;
  3139. // Start off with the server and namespace part
  3140. WString wsNormal;
  3141. try
  3142. {
  3143. wsNormal += L"\\\\";
  3144. if(AreWeLocal(pParsedPath->m_pServer))
  3145. wsNormal += L".";
  3146. else
  3147. wsNormal += pParsedPath->m_pServer;
  3148. wsNormal += L"\\";
  3149. WCHAR * pPath = pParsedPath->GetNamespacePart();
  3150. CVectorDeleteMe<WCHAR> dm1(pPath);
  3151. if(pPath)
  3152. wsNormal += pPath;
  3153. else
  3154. wsNormal += pNs->GetName();
  3155. wsNormal += L":";
  3156. // Find the parent that defined the key
  3157. // ====================================
  3158. IWbemClassObject *pCls = 0;
  3159. HRESULT hRes = CRepository::FindKeyRoot(pNs->GetNsSession(), pNs->GetScope(), pParsedPath->m_pClass, &pCls);
  3160. CReleaseMe rmRootCls(pCls);
  3161. if (hRes == WBEM_E_NOT_FOUND)
  3162. {
  3163. wsNormal += pParsedPath->m_pClass;
  3164. }
  3165. else if (SUCCEEDED(hRes))
  3166. {
  3167. CVar vName;
  3168. HRESULT getClassResult = ((CWbemClass *)pCls)->GetClassName(&vName);
  3169. if (FAILED(getClassResult))
  3170. return NULL;
  3171. wsNormal += vName.GetLPWSTR();
  3172. }
  3173. // Convert this part to upper-case
  3174. // ===============================
  3175. LPWSTR wsz = (wchar_t*)wsNormal;
  3176. SIZE_T Len = wsNormal.Length();
  3177. for(int i = 0; i < Len; i++)
  3178. {
  3179. wsz[i] = wbem_towupper(wsz[i]);
  3180. }
  3181. WCHAR * wszKey = pParsedPath->GetKeyString();
  3182. if (wszKey)
  3183. {
  3184. CVectorDeleteMe<WCHAR> dm2(wszKey);
  3185. wsNormal += L"=";
  3186. wsNormal += wszKey;
  3187. pReturnString = wsNormal.UnbindPtr();
  3188. }
  3189. }
  3190. catch (CX_MemoryException &)
  3191. {
  3192. // pReturnString is already NULL here
  3193. }
  3194. return pReturnString;
  3195. }
  3196. //***************************************************************************
  3197. //
  3198. //***************************************************************************
  3199. BOOL CQueryEngine::AreClassesRelated(CWbemNamespace* pNamespace,
  3200. IWbemContext* pContext,
  3201. CWbemObject* pClass1, LPCWSTR wszClass2)
  3202. {
  3203. HRESULT hres;
  3204. // First check if class 1 inherits from class 2
  3205. // ============================================
  3206. if(pClass1->InheritsFrom((LPWSTR)wszClass2) == S_OK)
  3207. return TRUE;
  3208. // Now, unfortunately, we have to go get the second class
  3209. // ======================================================
  3210. CSynchronousSink* pSink = CSynchronousSink::Create();
  3211. if (NULL == pSink) return FALSE;
  3212. pSink->AddRef();
  3213. CReleaseMe rm1(pSink);
  3214. hres = pNamespace->Exec_GetClass(wszClass2, 0, pContext, pSink);
  3215. if(FAILED(hres)) return FALSE;
  3216. pSink->Block();
  3217. pSink->GetStatus(&hres, NULL, NULL);
  3218. if(FAILED(hres)) return FALSE;
  3219. CWbemClass* pClass2 = (CWbemClass*)(pSink->GetObjects()[0]);
  3220. // Get the first class's name
  3221. // ==========================
  3222. CVar vFirstName;
  3223. if (FAILED(pClass1->GetClassName(&vFirstName)))
  3224. return FALSE;
  3225. // Check if the second class is derived from the first one
  3226. // =======================================================
  3227. if(pClass2->InheritsFrom(vFirstName.GetLPWSTR()) == S_OK)
  3228. return TRUE;
  3229. return FALSE;
  3230. }
  3231. //***************************************************************************
  3232. //
  3233. // Determines if property <wszPropName> in object <pObj>
  3234. // is a reference to <pTargetClass>
  3235. //
  3236. //***************************************************************************
  3237. BOOL CQueryEngine::IsAReferenceToClass(
  3238. CWbemNamespace* pNamespace,
  3239. IWbemContext* pContext,
  3240. CWbemObject* pObj,
  3241. LPCWSTR wszPropName,
  3242. CWbemObject* pTargetClass,
  3243. bool bCheckPropValue
  3244. )
  3245. {
  3246. // Get the cimtype
  3247. // ===============
  3248. CIMTYPE ct;
  3249. if(FAILED(pObj->GetPropertyType((LPWSTR)wszPropName, &ct)) ||
  3250. ct != CIM_REFERENCE)
  3251. {
  3252. return FALSE;
  3253. }
  3254. CVar vCimType;
  3255. if(FAILED(pObj->GetPropQualifier((LPWSTR)wszPropName, TYPEQUAL,
  3256. &vCimType)))
  3257. {
  3258. return FALSE;
  3259. }
  3260. // See if it is a reference
  3261. // ========================
  3262. if (!wbem_wcsicmp(vCimType.GetLPWSTR(), L"ref"))
  3263. {
  3264. // Special case of object refs which only refer to class definitions.
  3265. // ==================================================================
  3266. if (bCheckPropValue)
  3267. {
  3268. CVar vClassPath;
  3269. CVar vClassName;
  3270. int nRes = pObj->GetProperty(wszPropName, &vClassPath);
  3271. nRes = pTargetClass->GetClassName(&vClassName);
  3272. if (!vClassPath.IsNull() && !vClassPath.IsNull())
  3273. {
  3274. if (wbem_wcsicmp(vClassName.GetLPWSTR(), vClassPath.GetLPWSTR()) == 0)
  3275. return TRUE;
  3276. }
  3277. }
  3278. else
  3279. return TRUE;
  3280. }
  3281. if(wbem_wcsnicmp(vCimType.GetLPWSTR(), L"ref:", 4) == 0)
  3282. {
  3283. LPWSTR wszClass = vCimType.GetLPWSTR() + 4;
  3284. return CQueryEngine::AreClassesRelated(pNamespace, pContext,
  3285. pTargetClass, wszClass);
  3286. }
  3287. return FALSE;
  3288. }
  3289. //***************************************************************************
  3290. //
  3291. // CQueryEngine::KeyedQuery
  3292. //
  3293. // Preconditions:
  3294. // The query is known to contain all key properties with equality
  3295. // tests such that the object can be retrieved using
  3296. // CObjectDatabase::GetObjectByPath and subsequently filtered.
  3297. //
  3298. //***************************************************************************
  3299. // ok
  3300. int CQueryEngine::KeyedQuery(
  3301. IN IWmiDbSession *pSession,
  3302. IN IWmiDbHandle *pNsHandle,
  3303. IN QL_LEVEL_1_RPN_EXPRESSION *pExp,
  3304. IN CWbemObject *pClassDef,
  3305. IN DWORD dwFlags,
  3306. IN CBasicObjectSink* pDest, // no status
  3307. IN CWbemNamespace * pNs
  3308. )
  3309. {
  3310. int nRet = no_error;
  3311. // Convert the query into an object path.
  3312. // ======================================
  3313. wmilib::auto_buffer<WCHAR> pObjPath( GetObjectPathFromQuery(pClassDef, pExp, pNs));
  3314. if (NULL == pObjPath.get()) return invalid_query;
  3315. // Now get the object by path.
  3316. // ===========================
  3317. IWbemClassObject *pObj = 0;
  3318. HRESULT hRes = CRepository::GetObject(pSession, pNsHandle, pObjPath.get(), 0, &pObj);
  3319. CReleaseMe rmObj(pObj);
  3320. // If there was an object, test it against the 'rest' of the query.
  3321. // ================================================================
  3322. if (SUCCEEDED(hRes))
  3323. {
  3324. CQlFilteringSink* pFilteringSink = new CQlFilteringSink(pDest, pExp, pNs);
  3325. if (NULL == pFilteringSink) return failed;
  3326. pFilteringSink->AddRef();
  3327. // Indicate it in the Sink
  3328. pFilteringSink->Add(pObj);
  3329. pFilteringSink->Release();
  3330. }
  3331. return nRet;
  3332. }
  3333. //***************************************************************************
  3334. //
  3335. // CQueryEngine::GetObjectPathFromQuery
  3336. //
  3337. // Converts the relevant parts of a QL query to an equivalent object
  3338. // path. This assumes that the query contains equality tests on all
  3339. // key properties such that an object path would generate the same
  3340. // single instance as the query.
  3341. //
  3342. //***************************************************************************
  3343. // ok
  3344. LPWSTR CQueryEngine::GetObjectPathFromQuery(
  3345. IN CWbemObject *pClassDef,
  3346. IN QL_LEVEL_1_RPN_EXPRESSION *pExp,
  3347. IN CWbemNamespace * pNs
  3348. )
  3349. {
  3350. CWStringArray aKeys;
  3351. WString ObjPath;
  3352. CVar v;
  3353. HRESULT hr = pClassDef->GetClassName(&v);
  3354. if (FAILED(hr))
  3355. return 0;
  3356. ObjPath += v.GetLPWSTR();
  3357. ObjPath += L".";
  3358. pClassDef->GetKeyProps(aKeys);
  3359. BOOL bFirst = TRUE;
  3360. for (int i = 0; i < aKeys.Size(); i++)
  3361. {
  3362. if (!bFirst)
  3363. ObjPath += L",";
  3364. bFirst = FALSE;
  3365. ObjPath += aKeys[i];
  3366. ObjPath += L"=";
  3367. // Now find the property value.
  3368. // ============================
  3369. for (int i2 = 0; i2 < pExp->nNumTokens; i2++)
  3370. {
  3371. QL_LEVEL_1_TOKEN& Tok = pExp->pArrayOfTokens[i2];
  3372. LPWSTR wszPropName = GetSimplePropertyName(Tok.PropertyName);
  3373. if (Tok.nTokenType == QL_LEVEL_1_TOKEN::OP_EXPRESSION &&
  3374. wszPropName && wbem_wcsicmp(aKeys[i], wszPropName) == 0)
  3375. {
  3376. if (V_VT(&Tok.vConstValue) == VT_BSTR)
  3377. {
  3378. ObjPath += L"\"";
  3379. WString nonEscaped(V_BSTR(&Tok.vConstValue));
  3380. WString escaped = nonEscaped.EscapeQuotes();
  3381. ObjPath += escaped;
  3382. ObjPath += L"\"";
  3383. }
  3384. else if (V_VT(&Tok.vConstValue) == VT_BOOL)
  3385. {
  3386. short bValue = V_I2(&Tok.vConstValue);
  3387. if(bValue == VARIANT_TRUE)
  3388. ObjPath+= L"1";
  3389. else
  3390. ObjPath += L"0";
  3391. }
  3392. else
  3393. {
  3394. _variant_t varTo;
  3395. SCODE sc = VariantChangeType(&varTo, &Tok.vConstValue, 0, VT_BSTR);
  3396. if(sc == S_OK)
  3397. {
  3398. wchar_t buf[64];
  3399. StringCchPrintf(buf, 64, L"%s", varTo.bstrVal);
  3400. ObjPath += buf;
  3401. }
  3402. }
  3403. }
  3404. }
  3405. }
  3406. return ObjPath.UnbindPtr();
  3407. }
  3408. HRESULT CQueryEngine::FindOverridenProperties(CDynasty* pDyn,
  3409. CWStringArray& awsOverriden,
  3410. bool bIncludeThis)
  3411. {
  3412. //
  3413. // If this class is included (not top-level), add all the properties
  3414. // it overrides to the array
  3415. //
  3416. if(bIncludeThis)
  3417. {
  3418. CWbemObject *pTmp = (CWbemObject *) pDyn->m_pClassObj;
  3419. for(int i = 0; i < pTmp->GetNumProperties(); i++)
  3420. {
  3421. CVar vPropName;
  3422. pTmp->GetPropName(i, &vPropName);
  3423. CVar vOverride;
  3424. if(FAILED(pTmp->GetPropQualifier(vPropName.GetLPWSTR(),
  3425. L"OVERRIDEVALUE",
  3426. &vOverride)))
  3427. continue;
  3428. //
  3429. // Overriden property --- add
  3430. //
  3431. if (CFlexArray::no_error != awsOverriden.Add(vPropName.GetLPWSTR()))
  3432. {
  3433. continue;
  3434. }
  3435. }
  3436. }
  3437. //
  3438. // Recurse through all the children
  3439. //
  3440. for(int i = 0; i < pDyn->m_Children.Size(); i++)
  3441. {
  3442. CDynasty* pSubDyn = (CDynasty*)(pDyn->m_Children.GetAt(i));
  3443. HRESULT hres = FindOverridenProperties(pSubDyn, awsOverriden, true);
  3444. if(FAILED(hres))
  3445. return hres;
  3446. }
  3447. return WBEM_S_NO_ERROR;
  3448. }
  3449. //***************************************************************************
  3450. //
  3451. // CQueryEngine::ExecAtomicDynQlQuery
  3452. //
  3453. //***************************************************************************
  3454. // ok
  3455. HRESULT CQueryEngine::ExecAtomicDynQlQuery(
  3456. IN CWbemNamespace *pNs,
  3457. IN CDynasty* pDyn,
  3458. IN LPWSTR pszQueryFormat,
  3459. IN LPWSTR pszQuery,
  3460. IN QL_LEVEL_1_RPN_EXPRESSION *pParsedQuery,
  3461. IN LONG lFlags,
  3462. IN IWbemContext* pContext,
  3463. IN CBasicObjectSink* pDest, // must support selective filtering ,
  3464. IN BOOL bComplexQuery
  3465. )
  3466. {
  3467. HRESULT hres;
  3468. DEBUGTRACE((LOG_WBEMCORE,"Query Engine request: querying dyn provider with <%S>\n", pszQuery));
  3469. //
  3470. // Find all the properties that are overriden by derived classes.
  3471. // We must remove all references to those properties from the query, since
  3472. // otherwise this provider might not return the parent instances needed to
  3473. // merge with the child instances with the overriden property values.
  3474. //
  3475. CWStringArray awsOverriden;
  3476. hres = FindOverridenProperties(pDyn, awsOverriden);
  3477. if(FAILED(hres))
  3478. return pDest->Return(hres);
  3479. //
  3480. // Get the query analyzer to remove all the properties that are overriden
  3481. // or not members of this class (not possible right now anyway)
  3482. //
  3483. QL_LEVEL_1_RPN_EXPRESSION* pNewParsedQuery = NULL;
  3484. hres = CQueryAnalyser::GetNecessaryQueryForClass(pParsedQuery,
  3485. pDyn->m_pClassObj, awsOverriden, pNewParsedQuery);
  3486. if(FAILED(hres)) return pDest->Return(hres);
  3487. CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm1(pNewParsedQuery);
  3488. //
  3489. // Get the new text to give to provider
  3490. //
  3491. LPWSTR pszNewQuery = pNewParsedQuery->GetText();
  3492. if(pszNewQuery == NULL) return WBEM_E_OUT_OF_MEMORY;
  3493. CVectorDeleteMe<WCHAR> vdm(pszNewQuery);
  3494. DEBUGTRACE((LOG_WBEMCORE,"Query Engine actual: querying dyn provider with <%S>\n", pszNewQuery));
  3495. // Check if the query is empty
  3496. // ===========================
  3497. BOOL bEmpty = FALSE;
  3498. if(lFlags & WBEM_FLAG_SHALLOW)
  3499. {
  3500. // We know that the query is actually a shallow enumeration
  3501. // ========================================================
  3502. bEmpty = TRUE;
  3503. }
  3504. else if(pNewParsedQuery == NULL ||
  3505. (pNewParsedQuery->nNumTokens == 0 &&
  3506. pNewParsedQuery->nNumberOfProperties == 0))
  3507. {
  3508. bEmpty = TRUE;
  3509. }
  3510. if(bEmpty)
  3511. {
  3512. pNs->DynAux_GetInstances (
  3513. (CWbemObject *) pDyn->m_pClassObj, // class def
  3514. lFlags & ~WBEM_FLAG_SHALLOW, // used for WBEM_FLAG_SEND_STATUS
  3515. pContext,
  3516. pDest,
  3517. bComplexQuery
  3518. );
  3519. }
  3520. else
  3521. {
  3522. pNs->DynAux_ExecQueryAsync (
  3523. (CWbemObject *) pDyn->m_pClassObj,
  3524. pszNewQuery,
  3525. pszQueryFormat,
  3526. lFlags & ~WBEM_FLAG_SHALLOW,
  3527. pContext,
  3528. pDest,
  3529. bComplexQuery
  3530. ) ;
  3531. }
  3532. return WBEM_S_NO_ERROR;
  3533. }
  3534. HRESULT CQueryEngine::EliminateDuplications(
  3535. CRefedPointerArray<CWbemClass>& apClasses,
  3536. LPCWSTR wszResultClass)
  3537. {
  3538. int i;
  3539. if(wszResultClass)
  3540. {
  3541. // Eliminate all classes not derived from wszResultClass
  3542. // =====================================================
  3543. for(i = 0; i < apClasses.GetSize(); i++)
  3544. {
  3545. if(apClasses[i]->InheritsFrom((LPWSTR)wszResultClass) !=
  3546. WBEM_S_NO_ERROR)
  3547. {
  3548. // Not derived
  3549. apClasses.RemoveAt(i);
  3550. i--;
  3551. }
  3552. }
  3553. }
  3554. for(i = 0; i < apClasses.GetSize(); i++)
  3555. {
  3556. // Check if this class is abstract. There is no reason asking abstract
  3557. // classes for their objects
  3558. // ===================================================================
  3559. CVar vAbstract;
  3560. if(SUCCEEDED(apClasses[i]->GetQualifier(L"abstract", &vAbstract))
  3561. && vAbstract.GetType() == VT_BOOL && vAbstract.GetBool())
  3562. {
  3563. apClasses.RemoveAt(i);
  3564. i--;
  3565. }
  3566. }
  3567. // Search for pairs // TBD: can be done more efficiently!!
  3568. // =======================================================
  3569. for(i = 0; i < apClasses.GetSize(); i++)
  3570. {
  3571. CWbemClass* pClass1 = apClasses[i];
  3572. if(pClass1 == NULL)
  3573. continue;
  3574. CVar vName;
  3575. apClasses[i]->GetClassName(&vName);
  3576. for (int j = 0; j < apClasses.GetSize(); j++)
  3577. {
  3578. if(j == i) continue;
  3579. CWbemClass* pClass2 = apClasses[j];
  3580. if(pClass2 == NULL)
  3581. continue;
  3582. if (pClass2->InheritsFrom(vName.GetLPWSTR()) == WBEM_S_NO_ERROR)
  3583. {
  3584. // Eliminate class 2 --- it's parent is listed
  3585. // ===========================================
  3586. apClasses.SetAt(j, NULL);
  3587. }
  3588. }
  3589. }
  3590. return WBEM_S_NO_ERROR;
  3591. }
  3592. //***************************************************************************
  3593. //
  3594. //***************************************************************************
  3595. LPWSTR CQueryEngine::GetPrimaryName(WBEM_PROPERTY_NAME& Name)
  3596. {
  3597. if(Name.m_lNumElements < 1 ||
  3598. Name.m_aElements[0].m_nType != WBEM_NAME_ELEMENT_TYPE_PROPERTY)
  3599. {
  3600. return NULL;
  3601. }
  3602. return Name.m_aElements[0].Element.m_wszPropertyName;
  3603. }
  3604. //***************************************************************************
  3605. //
  3606. //***************************************************************************
  3607. LPWSTR CQueryEngine::GetSimplePropertyName(WBEM_PROPERTY_NAME& Name)
  3608. {
  3609. if(Name.m_lNumElements != 1 ||
  3610. Name.m_aElements[0].m_nType != WBEM_NAME_ELEMENT_TYPE_PROPERTY)
  3611. {
  3612. return NULL;
  3613. }
  3614. return Name.m_aElements[0].Element.m_wszPropertyName;
  3615. }
  3616. //***************************************************************************
  3617. //
  3618. //***************************************************************************
  3619. HRESULT CQueryEngine::ExecSchemaQuery( IN CWbemNamespace *pNs,
  3620. IN LPWSTR pszQuery,
  3621. QL_LEVEL_1_RPN_EXPRESSION *pExp,
  3622. IN IWbemContext* pContext,
  3623. IN CBasicObjectSink* pSink)
  3624. {
  3625. HRESULT hres = WBEM_S_NO_ERROR;
  3626. if (pExp->nNumTokens == 0)
  3627. {
  3628. //This means we want all classes...
  3629. pNs->Exec_CreateClassEnum(NULL, 0, pContext, pSink);
  3630. return WBEM_S_NO_ERROR;
  3631. }
  3632. else if ((pExp->nNumTokens == 1) &&
  3633. (pExp->pArrayOfTokens[0].nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL))
  3634. {
  3635. //This means we have a simple expression (hopefully)
  3636. //Now we need to check which type of retrieval we are looking for...
  3637. LPCWSTR szPropName = pExp->pArrayOfTokens[0].PropertyName.GetStringAt(0);
  3638. VARIANT& vValue = pExp->pArrayOfTokens[0].vConstValue;
  3639. if (szPropName == 0)
  3640. return pSink->Return(WBEM_E_INVALID_QUERY);
  3641. if (wbem_wcsicmp(szPropName, L"__CLASS") == 0)
  3642. {
  3643. if ((V_VT(&vValue) == VT_BSTR) && (wcslen(V_BSTR(&vValue)))) // SEC:REVIEWED 2002-03-22 : Needs EH or NULL test
  3644. {
  3645. //Single class retrieval
  3646. CErrorChangingSink Err(pSink, WBEM_E_NOT_FOUND, 0);
  3647. pNs->Exec_GetObject(V_BSTR(&vValue), 0, pContext, &Err);
  3648. return WBEM_S_NO_ERROR;
  3649. }
  3650. else if((V_VT(&vValue) == VT_NULL) ||
  3651. ((V_VT(&vValue) == VT_BSTR) && (wcslen(V_BSTR(&vValue))==0))) // SEC:REVIEWED 2002-03-22 : Needs EH or NULL test
  3652. {
  3653. // __CLASS = NULL
  3654. return pSink->Return(WBEM_S_NO_ERROR);
  3655. }
  3656. else
  3657. {
  3658. return pSink->Return(WBEM_E_INVALID_QUERY);
  3659. }
  3660. }
  3661. else if (wbem_wcsicmp(szPropName, L"__SUPERCLASS") == 0)
  3662. {
  3663. if(V_VT(&vValue) == VT_BSTR)
  3664. {
  3665. CErrorChangingSink Err(pSink, WBEM_E_INVALID_CLASS, 0);
  3666. //Get things which are hanging off these items
  3667. pNs->Exec_CreateClassEnum(V_BSTR(&vValue), WBEM_FLAG_SHALLOW,
  3668. pContext, &Err);
  3669. }
  3670. else if(V_VT(&vValue) == VT_NULL)
  3671. {
  3672. // get things which are hanging off root
  3673. pNs->Exec_CreateClassEnum(L"", WBEM_FLAG_SHALLOW,
  3674. pContext, pSink);
  3675. }
  3676. else
  3677. {
  3678. pSink->Return(WBEM_E_INVALID_QUERY);
  3679. }
  3680. return WBEM_S_NO_ERROR;
  3681. }
  3682. else if (wbem_wcsicmp(szPropName, L"__DYNASTY") == 0)
  3683. {
  3684. if(V_VT(&vValue) == VT_BSTR)
  3685. {
  3686. //Get things which are hanging off these items as well as the item itself
  3687. BSTR strClassName = V_BSTR(&vValue);
  3688. IWbemClassObject* pClass = NULL;
  3689. hres = pNs->Exec_GetObjectByPath(strClassName, 0, pContext,&pClass, NULL);
  3690. CReleaseMe rmCls(pClass);
  3691. if(FAILED(hres))
  3692. {
  3693. if(hres == WBEM_E_NOT_FOUND)
  3694. hres = S_OK;
  3695. return pSink->Return(hres);
  3696. }
  3697. else // restore the value
  3698. {
  3699. hres = WBEM_S_NO_ERROR;
  3700. }
  3701. // Check that this is the root of the dynasty
  3702. CVar vDyn;
  3703. if(FAILED(((CWbemObject*)pClass)->GetDynasty(&vDyn)))
  3704. return pSink->Return(WBEM_E_FAILED);
  3705. if (vDyn.IsNull())
  3706. return pSink->Return(WBEM_S_NO_ERROR);
  3707. if(wbem_wcsicmp(vDyn.GetLPWSTR(), strClassName))
  3708. return pSink->Return(WBEM_S_NO_ERROR);
  3709. pSink->Add(pClass);
  3710. pNs->Exec_CreateClassEnum(strClassName, 0, pContext, pSink);
  3711. }
  3712. else if(V_VT(&vValue) == VT_NULL)
  3713. {
  3714. pSink->Return(WBEM_S_NO_ERROR);
  3715. }
  3716. else
  3717. {
  3718. pSink->Return(WBEM_E_INVALID_QUERY);
  3719. }
  3720. return WBEM_S_NO_ERROR;
  3721. }
  3722. else
  3723. {
  3724. return pSink->Return(WBEM_E_INVALID_QUERY);
  3725. }
  3726. }
  3727. else if ((pExp->nNumTokens == 1) &&
  3728. (pExp->pArrayOfTokens[0].nOperator == QL1_OPERATOR_ISA) &&
  3729. (wbem_wcsicmp(pExp->pArrayOfTokens[0].PropertyName.GetStringAt(0), L"__THIS") == 0))
  3730. {
  3731. //With the isa, we return everything which is derived from this, as well
  3732. //as the class in question...
  3733. VARIANT & var = pExp->pArrayOfTokens[0].vConstValue;
  3734. if(var.vt != VT_BSTR || var.bstrVal == 0)
  3735. return pSink->Return(WBEM_E_INVALID_QUERY);
  3736. CCombiningSink* pCombiningSink = new CCombiningSink(pSink, WBEM_E_NOT_FOUND);
  3737. if (NULL == pCombiningSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  3738. pCombiningSink->AddRef();
  3739. CReleaseMe rmCombSink(pCombiningSink);
  3740. pNs->Exec_GetObject(V_BSTR(&(pExp->pArrayOfTokens[0].vConstValue)), 0, pContext, pCombiningSink);
  3741. pNs->Exec_CreateClassEnum(V_BSTR(&(pExp->pArrayOfTokens[0].vConstValue)), 0, pContext, pCombiningSink);
  3742. return WBEM_S_NO_ERROR;
  3743. }
  3744. // OK, so all the simple cases are dealt with here. We should now check everything is
  3745. // valid and process it in the best possible way. If this is a conjunctive query
  3746. // we can also do a little optimisation!
  3747. //Lets validate all of the properties to make sure they are all valid. If we
  3748. //did not do this, there are scenarios where we would get inconsistencies
  3749. //based on the different code paths.
  3750. BOOL bError = FALSE;
  3751. //While we are at it, we can do a check for the first location of each type of property
  3752. //name (this is used for optimisation!)
  3753. BOOL bConjunctive = IsConjunctiveQuery(pExp);
  3754. QL_LEVEL_1_TOKEN *pThisToken = NULL,
  3755. *pClassToken = NULL,
  3756. *pSuperclassToken = NULL,
  3757. *pDynastyToken = NULL;
  3758. for (int i = 0; i != pExp->nNumTokens; i++)
  3759. {
  3760. QL_LEVEL_1_TOKEN* pCurrentToken = pExp->pArrayOfTokens + i;
  3761. if (pCurrentToken->PropertyName.GetNumElements() > 1)
  3762. {
  3763. //This is probably an error!
  3764. bError = TRUE;
  3765. break;
  3766. }
  3767. else if (pCurrentToken->PropertyName.GetNumElements() == 1)
  3768. {
  3769. //We need to validate it...
  3770. //If it is an isa, it can only be a "__this", otherwise it has to be one
  3771. //of the "__superclass", "__dynasty" or "__class"
  3772. LPCWSTR wszCurrentPropName = pCurrentToken->PropertyName.GetStringAt(0);
  3773. if (wszCurrentPropName == 0)
  3774. {
  3775. bError = TRUE;
  3776. break;
  3777. }
  3778. if (pCurrentToken->nOperator == QL1_OPERATOR_ISA)
  3779. {
  3780. if(wbem_wcsicmp(wszCurrentPropName, L"__THIS"))
  3781. {
  3782. bError = TRUE;
  3783. break;
  3784. }
  3785. }
  3786. else
  3787. {
  3788. if(wbem_wcsicmp(wszCurrentPropName, L"__CLASS") &&
  3789. wbem_wcsicmp(wszCurrentPropName, L"__SUPERCLASS") &&
  3790. wbem_wcsicmp(wszCurrentPropName, L"__DYNASTY"))
  3791. {
  3792. bError = TRUE;
  3793. break;
  3794. }
  3795. }
  3796. if (bConjunctive)
  3797. {
  3798. VARIANT* pCurrentValue = &(pCurrentToken->vConstValue);
  3799. if (wbem_wcsicmp(wszCurrentPropName, L"__THIS") == 0)
  3800. {
  3801. if(V_VT(pCurrentValue) != VT_BSTR)
  3802. bError = TRUE;
  3803. else if (!pThisToken)
  3804. pThisToken = pCurrentToken;
  3805. }
  3806. else if (wbem_wcsicmp(wszCurrentPropName, L"__CLASS") == 0)
  3807. {
  3808. if(V_VT(pCurrentValue) != VT_BSTR && V_VT(pCurrentValue) != VT_NULL)
  3809. bError = TRUE;
  3810. else if (pCurrentToken->nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL)
  3811. bConjunctive = FALSE;
  3812. else if (!pClassToken)
  3813. pClassToken = pCurrentToken;
  3814. }
  3815. else if (wbem_wcsicmp(wszCurrentPropName, L"__SUPERCLASS") == 0)
  3816. {
  3817. if(V_VT(pCurrentValue) != VT_BSTR && V_VT(pCurrentValue) != VT_NULL)
  3818. bError = TRUE;
  3819. else if (pCurrentToken->nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL)
  3820. bConjunctive = FALSE;
  3821. else if (!pSuperclassToken)
  3822. pSuperclassToken = pCurrentToken;
  3823. }
  3824. else // DYNASTY
  3825. {
  3826. if(V_VT(pCurrentValue) != VT_BSTR)
  3827. bError = TRUE;
  3828. else if (pCurrentToken->nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL)
  3829. bConjunctive = FALSE;
  3830. else if (!pDynastyToken)
  3831. pDynastyToken = pCurrentToken;
  3832. }
  3833. }
  3834. }
  3835. }
  3836. if (bError == TRUE) return pSink->Return(WBEM_E_INVALID_QUERY);
  3837. //We need to create a filter sink to deal with this query....
  3838. CQlFilteringSink* pFilteringSink = new CQlFilteringSink(pSink, pExp, pNs, TRUE);
  3839. if (NULL == pFilteringSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  3840. pFilteringSink->AddRef();
  3841. CReleaseMe rmFilter(pFilteringSink);
  3842. //If this is conjunctive we can just retrieve a single item based on a set of
  3843. //rules and pass this through the filter
  3844. if (bConjunctive)
  3845. {
  3846. //We can pick a single item to retrieve and pass this through the filter rather
  3847. //than retrieve all of them
  3848. if (pClassToken)
  3849. {
  3850. //Single class retrieval
  3851. if(V_VT(&(pClassToken->vConstValue)) == VT_NULL)
  3852. {
  3853. // null class --- no such thing
  3854. pFilteringSink->Return(WBEM_S_NO_ERROR);
  3855. }
  3856. else // VT_BSTR
  3857. {
  3858. pNs->Exec_GetObject(V_BSTR(&(pClassToken->vConstValue)), 0,
  3859. pContext, pFilteringSink);
  3860. }
  3861. }
  3862. else if (pSuperclassToken)
  3863. {
  3864. //Get things which are hanging off these items
  3865. BSTR strParent = NULL;
  3866. if(V_VT(&(pSuperclassToken->vConstValue)) == VT_NULL)
  3867. {
  3868. // null superclass
  3869. strParent = NULL;
  3870. }
  3871. else // VT_BSTR
  3872. {
  3873. strParent = V_BSTR(&(pSuperclassToken->vConstValue));
  3874. }
  3875. pNs->Exec_CreateClassEnum(strParent, 0, pContext, pFilteringSink);
  3876. }
  3877. else if (pDynastyToken)
  3878. {
  3879. //Get things which are hanging off these items and the item itself
  3880. CCombiningSink* pCombiningSink = new CCombiningSink(pFilteringSink, WBEM_E_NOT_FOUND);
  3881. if (NULL == pCombiningSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  3882. rmFilter.release(); // Combining Took Ownership
  3883. pCombiningSink->AddRef();
  3884. // Guaranteed to be VT_BSTR
  3885. pNs->Exec_GetObject(V_BSTR(&(pDynastyToken->vConstValue)), 0, pContext, pCombiningSink);
  3886. pNs->Exec_CreateClassEnum(V_BSTR(&(pDynastyToken->vConstValue)), 0, pContext, pCombiningSink);
  3887. pCombiningSink->Release();
  3888. }
  3889. else if (pThisToken)
  3890. {
  3891. CCombiningSink* pCombiningSink = new CCombiningSink(pFilteringSink, WBEM_E_NOT_FOUND);
  3892. if (NULL == pCombiningSink) return pSink->Return(WBEM_E_OUT_OF_MEMORY);
  3893. rmFilter.release(); // Combining Took Ownership
  3894. pCombiningSink->AddRef();
  3895. // Guaranteed to be VT_BSTR
  3896. pNs->Exec_GetObject(V_BSTR(&(pThisToken->vConstValue)), 0, pContext, pCombiningSink);
  3897. pNs->Exec_CreateClassEnum(V_BSTR(&(pThisToken->vConstValue)), 0, pContext, pCombiningSink);
  3898. pCombiningSink->Release();
  3899. }
  3900. else
  3901. {
  3902. //Something strange here!
  3903. pNs->Exec_CreateClassEnum(NULL, 0, pContext, pFilteringSink);
  3904. }
  3905. }
  3906. else
  3907. {
  3908. //We need to retrieve all of them and pass through the filter.
  3909. pNs->Exec_CreateClassEnum(NULL, 0, pContext, pFilteringSink);
  3910. }
  3911. return hres;
  3912. }
  3913. // ****************************************************************************
  3914. //
  3915. // CQueryEngine::ValidateQuery
  3916. //
  3917. // This function makes sure that the data type of the property matches
  3918. // that of the const.
  3919. //
  3920. // ****************************************************************************
  3921. HRESULT CQueryEngine::ValidateQuery(IN QL_LEVEL_1_RPN_EXPRESSION *pExpr,
  3922. IN CWbemClass *pClassDef)
  3923. {
  3924. HRESULT hr = WBEM_S_NO_ERROR;
  3925. for(int i = 0; i < pExpr->nNumTokens; i++)
  3926. {
  3927. QL_LEVEL_1_TOKEN Token = pExpr->pArrayOfTokens[i];
  3928. if (Token.nTokenType == QL1_OP_EXPRESSION)
  3929. {
  3930. WBEM_WSTR wszCimType;
  3931. VARIANT PropVal;
  3932. VariantInit(&PropVal);
  3933. // Make sure this property exists.
  3934. // ===============================
  3935. hr = pClassDef->GetPropertyValue(&Token.PropertyName, 0,
  3936. &wszCimType, &PropVal);
  3937. // If we haven't found it, that's OK... it could
  3938. // be a weakly-typed embedded object.
  3939. if (FAILED(hr))
  3940. {
  3941. hr = WBEM_S_NO_ERROR;
  3942. continue;
  3943. }
  3944. switch(Token.nOperator)
  3945. {
  3946. // These only apply to embedded objects.
  3947. case QL1_OPERATOR_ISA:
  3948. case QL1_OPERATOR_ISNOTA:
  3949. case QL1_OPERATOR_INV_ISA:
  3950. case QL1_OPERATOR_INV_ISNOTA:
  3951. if(V_VT(&PropVal)!= VT_EMBEDDED_OBJECT)
  3952. {
  3953. if (wszCimType != NULL)
  3954. {
  3955. wchar_t wszTemp[7];
  3956. wcsncpy(wszTemp, wszCimType, 6); // SEC:REVIEWED 2002-03-22 : Fix this code to be more reasonable / RAID 591466
  3957. wszTemp[6] = '\0';
  3958. if (wcscmp(wszTemp, L"object"))
  3959. hr = WBEM_E_INVALID_QUERY;
  3960. }
  3961. else
  3962. hr = WBEM_E_INVALID_QUERY;
  3963. if (Token.vConstValue.vt == VT_NULL ||
  3964. Token.vConstValue.vt == VT_EMPTY)
  3965. hr = WBEM_E_INVALID_QUERY;
  3966. }
  3967. break;
  3968. default:
  3969. break;
  3970. }
  3971. VariantClear(&PropVal);
  3972. WbemStringFree(wszCimType);
  3973. }
  3974. if (hr != WBEM_S_NO_ERROR)
  3975. break;
  3976. }
  3977. // We don't support WITHIN!
  3978. if (pExpr->Tolerance.m_bExact == FALSE)
  3979. {
  3980. hr = WBEM_E_INVALID_QUERY;
  3981. }
  3982. return hr;
  3983. }
  3984. //***************************************************************************
  3985. //
  3986. //***************************************************************************
  3987. //
  3988. HRESULT CQueryEngine::ExecRepositoryQuery(
  3989. IN CWbemNamespace *pNs,
  3990. IN LPWSTR pszQuery,
  3991. IN LONG lFlags,
  3992. IN IWbemContext* pContext,
  3993. IN CBasicObjectSink* pSink
  3994. )
  3995. {
  3996. HRESULT hRes;
  3997. // Also, add check hierarchy for dynamic instances which need deleting
  3998. // Should we simulate by a prior enum and then executing individual delete instance
  3999. // calls? Would be a big performance drain, possibly.
  4000. hRes = CRepository::ExecQuery(pNs->GetNsSession(), pNs->GetScope(), pszQuery, pSink, 0);
  4001. return hRes;
  4002. }