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.

2967 lines
77 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. SQLDriver.cpp
  5. Abstract:
  6. Code for the core SQLEngine.
  7. Author:
  8. kinshu created Oct. 26, 2001
  9. Algo: From the sql string passed to the driver, we first of all create the show list
  10. (Statment::AttributeShowList), which is the list of attributes which are in
  11. SELECT clause. We then create a prefix expression, from the prefix we create a
  12. post fix and for every entry in the databases for which we wish to run the
  13. query we see if the entry satsifies this postfix notation, if it does then we
  14. make a result item(RESULT_ITEM) comprising of the entry and the database and
  15. add this result item in the result set.
  16. Once we have obtained the result set, for every entry and database combination in the
  17. result set we then obtain the values of the various attributes in the show list by
  18. giving the database and the entry. A row is actually an array of PNODE type
  19. This will be a row of results.
  20. All operators of our SQL are binary
  21. --*/
  22. #include "precomp.h"
  23. //////////////////////// Externs //////////////////////////////////////////////
  24. extern BOOL g_bMainAppExpanded;
  25. extern CRITICAL_SECTION g_csInstalledList;
  26. ///////////////////////////////////////////////////////////////////////////////
  27. //////////////////////// Defines //////////////////////////////////////////////
  28. //*******************************************************************************
  29. #define CHECK_OPERAND_TYPE(bOk,End) \
  30. { \
  31. if (pOperandLeft->dtType != pOperandRight->dtType) { \
  32. uErrorCode = ERROR_OPERANDS_DONOTMATCH; \
  33. bOk = FALSE; \
  34. goto End; \
  35. } \
  36. }
  37. //*******************************************************************************
  38. ///////////////////////////////////////////////////////////////////////////////
  39. //////////////////////// Global Variables /////////////////////////////////////
  40. // All the attributes that can be in SELECT clause of SQL
  41. struct _tagAttributeShowMapping AttributeShowMapping[] = {
  42. TEXT("APP_NAME"), ATTR_S_APP_NAME, IDS_ATTR_S_APP_NAME,
  43. TEXT("PROGRAM_NAME"), ATTR_S_ENTRY_EXEPATH, IDS_ATTR_S_ENTRY_EXEPATH,
  44. TEXT("PROGRAM_DISABLED"), ATTR_S_ENTRY_DISABLED, IDS_ATTR_S_ENTRY_DISABLED,
  45. TEXT("PROGRAM_GUID"), ATTR_S_ENTRY_GUID, IDS_ATTR_S_ENTRY_GUID,
  46. TEXT("PROGRAM_APPHELPTYPE"), ATTR_S_ENTRY_APPHELPTYPE, IDS_ATTR_S_ENTRY_APPHELPTYPE,
  47. TEXT("PROGRAM_APPHELPUSED"), ATTR_S_ENTRY_APPHELPUSED, IDS_ATTR_S_ENTRY_APPHELPUSED,
  48. TEXT("FIX_COUNT"), ATTR_S_ENTRY_SHIMFLAG_COUNT, IDS_ATTR_S_ENTRY_SHIMFLAG_COUNT,
  49. TEXT("PATCH_COUNT"), ATTR_S_ENTRY_PATCH_COUNT, IDS_ATTR_S_ENTRY_PATCH_COUNT,
  50. TEXT("MODE_COUNT"), ATTR_S_ENTRY_LAYER_COUNT, IDS_ATTR_S_ENTRY_LAYER_COUNT,
  51. TEXT("MATCH_COUNT"), ATTR_S_ENTRY_MATCH_COUNT, IDS_ATTR_S_ENTRY_MATCH_COUNT,
  52. TEXT("DATABASE_NAME"), ATTR_S_DATABASE_NAME, IDS_ATTR_S_DATABASE_NAME,
  53. TEXT("DATABASE_PATH"), ATTR_S_DATABASE_PATH, IDS_ATTR_S_DATABASE_PATH,
  54. TEXT("DATABASE_INSTALLED"), ATTR_S_DATABASE_INSTALLED, IDS_ATTR_S_DATABASE_INSTALLED,
  55. TEXT("DATABASE_GUID"), ATTR_S_DATABASE_GUID, IDS_ATTR_S_DATABASE_GUID,
  56. TEXT("FIX_NAME"), ATTR_S_SHIM_NAME, IDS_ATTR_S_SHIM_NAME,
  57. TEXT("MATCHFILE_NAME"), ATTR_S_MATCHFILE_NAME, IDS_ATTR_S_MATCHFILE_NAME,
  58. TEXT("MODE_NAME"), ATTR_S_LAYER_NAME, IDS_ATTR_S_LAYER_NAME,
  59. TEXT("PATCH_NAME"), ATTR_S_PATCH_NAME, IDS_ATTR_S_PATCH_NAME
  60. };
  61. // All the attributes that can be in WHERE clause of SQL
  62. struct _tagAttributeMatchMapping AttributeMatchMapping[] = {
  63. TEXT("APP_NAME"), ATTR_M_APP_NAME,
  64. TEXT("PROGRAM_NAME"), ATTR_M_ENTRY_EXEPATH,
  65. TEXT("PROGRAM_DISABLED"), ATTR_M_ENTRY_DISABLED,
  66. TEXT("PROGRAM_GUID"), ATTR_M_ENTRY_GUID,
  67. TEXT("PROGRAM_APPHELPTYPE"), ATTR_M_ENTRY_APPHELPTYPE,
  68. TEXT("PROGRAM_APPHELPUSED"), ATTR_M_ENTRY_APPHELPUSED,
  69. TEXT("FIX_COUNT"), ATTR_M_ENTRY_SHIMFLAG_COUNT,
  70. TEXT("PATCH_COUNT"), ATTR_M_ENTRY_PATCH_COUNT,
  71. TEXT("MODE_COUNT"), ATTR_M_ENTRY_LAYER_COUNT,
  72. TEXT("MATCH_COUNT"), ATTR_M_ENTRY_MATCH_COUNT,
  73. TEXT("DATABASE_NAME"), ATTR_M_DATABASE_NAME,
  74. TEXT("DATABASE_PATH"), ATTR_M_DATABASE_PATH,
  75. TEXT("DATABASE_INSTALLED"), ATTR_M_DATABASE_INSTALLED,
  76. TEXT("DATABASE_GUID"), ATTR_M_DATABASE_GUID,
  77. TEXT("FIX_NAME"), ATTR_M_SHIM_NAME,
  78. TEXT("MATCHFILE_NAME"), ATTR_M_MATCHFILE_NAME,
  79. TEXT("MODE_NAME"), ATTR_M_LAYER_NAME,
  80. TEXT("PATCH_NAME"), ATTR_M_PATCH_NAME
  81. };
  82. //
  83. // Map the sql database names to the database types
  84. // Check for references to DatabasesMapping before changing order
  85. struct _tagDatabasesMapping DatabasesMapping[3] = {
  86. TEXT("SYSTEM_DB"), DATABASE_TYPE_GLOBAL,
  87. TEXT("INSTALLED_DB"), DATABASE_TYPE_INSTALLED,
  88. TEXT("CUSTOM_DB"), DATABASE_TYPE_WORKING
  89. };
  90. // All our SQL operators
  91. struct _tagOperatorMapping OperatorMapping[] = {
  92. TEXT(">"), OPER_GT, 4,
  93. TEXT("<"), OPER_LT, 4,
  94. TEXT(">="), OPER_GE, 4,
  95. TEXT("<="), OPER_LE, 4,
  96. TEXT("<>"), OPER_NE, 4,
  97. TEXT("="), OPER_EQUAL, 4,
  98. TEXT("CONTAINS"), OPER_CONTAINS, 4,
  99. TEXT("HAS"), OPER_HAS, 4,
  100. TEXT("OR"), OPER_OR, 3,
  101. TEXT("AND"), OPER_AND, 3
  102. };
  103. // The SQL constants
  104. struct _tagConstants Constants[] = {
  105. TEXT("TRUE"), DT_LITERAL_BOOL, 1,
  106. TEXT("FALSE"), DT_LITERAL_BOOL, 0,
  107. TEXT("BLOCK"), DT_LITERAL_INT, APPTYPE_INC_HARDBLOCK,
  108. TEXT("NOBLOCK"), DT_LITERAL_INT, APPTYPE_INC_NOBLOCK
  109. };
  110. //////////////////////// Function Declarations ////////////////////////////////
  111. ///////////////////////////////////////////////////////////////////////////////
  112. void
  113. Statement::SetWindow(
  114. IN HWND hWnd
  115. )
  116. /*++
  117. Statement::SetWindow
  118. Desc: Associates a window with the Statement. This will be the UI window, so that
  119. we can change some status from the methods of the statement class
  120. Params:
  121. IN HWND hWnd: The handle to the query db window. This is the GUI for the
  122. SQL driver
  123. --*/
  124. {
  125. m_hdlg = hWnd;
  126. }
  127. BOOL
  128. Statement::CreateAttributesShowList(
  129. IN OUT TCHAR* pszSQL,
  130. OUT BOOL* pbFromFound
  131. )
  132. /*++
  133. Statement::CreateAttributesShowList
  134. Desc: Creates the show list for the sql. The show list is the list of nodes that
  135. should be shown in the result. This routine creates the AttributeShowList
  136. for the present Statement using the attributes in the SELECT clause.
  137. Params:
  138. IN OUT TCHAR* pszSQL: The complete SQL
  139. OUT BOOL* pbFromFound: Did we find a FROM in the SQL
  140. Return:
  141. TRUE: Everything OK, we created a valid show-list
  142. FALSE: Otherwise
  143. Notes: SELECT * is allowed, if we do SELECT x,* all the attributes will
  144. still be shown just once.
  145. --*/
  146. {
  147. BOOL bOk = TRUE;
  148. TCHAR* pszCurrent = NULL; // Pointer to the present token
  149. PNODE pNode = NULL;
  150. BOOL fFound = FALSE;
  151. pszCurrent = _tcstok(pszSQL, TEXT(" ,\t\n"));
  152. if (lstrcmpi(pszCurrent, TEXT("SELECT")) != 0) {
  153. //
  154. // Error: Select not found.
  155. //
  156. this->uErrorCode = ERROR_SELECT_NOTFOUND;
  157. bOk = FALSE;
  158. goto Cleanup;
  159. }
  160. //
  161. // Warning: strtok family of functions uses a static variable for parsing the string into tokens.
  162. // If multiple or simultaneous calls are made to the same function,
  163. // a high potential for data corruption and inaccurate results exists.
  164. // Therefore, do not attempt to call the same function simultaneously for
  165. // different strings and be aware of calling one of these function from within a loop
  166. // where another routine may be called that uses the same function.
  167. // However, calling this function simultaneously from multiple threads
  168. // does not have undesirable effects.
  169. //
  170. // Now we create the strlAttributeShowList properly.
  171. //
  172. while (pszCurrent = _tcstok(NULL, TEXT(" ,\t\n"))) {
  173. fFound = FALSE;
  174. for (UINT uIndex = 0; uIndex < ARRAYSIZE(AttributeShowMapping); ++uIndex) {
  175. if (lstrcmpi(AttributeShowMapping[uIndex].szAttribute, pszCurrent) == 0) {
  176. pNode = new NODE(DT_ATTRSHOW, AttributeShowMapping[uIndex].attr);
  177. if (pNode == NULL) {
  178. MEM_ERR;
  179. bOk = FALSE;
  180. goto Cleanup;
  181. }
  182. AttributeShowList.AddAtEnd(pNode);
  183. fFound = TRUE;
  184. }
  185. }
  186. if (fFound == FALSE) {
  187. if (lstrcmp(pszCurrent, TEXT("*")) == 0) {
  188. SelectAll();
  189. fFound = TRUE;
  190. } else if (lstrcmpi(pszCurrent, TEXT("FROM")) == 0) {
  191. *pbFromFound = TRUE;
  192. bOk = TRUE;
  193. fFound = TRUE;
  194. goto Cleanup;
  195. }
  196. }
  197. if (fFound == FALSE) {
  198. uErrorCode = ERROR_INVALID_SELECTPARAM;
  199. bOk = FALSE;
  200. goto Cleanup;
  201. }
  202. }
  203. Cleanup:
  204. if (AttributeShowList.m_uCount == 0) {
  205. uErrorCode = ERROR_INVALID_SELECTPARAM;
  206. bOk = FALSE;
  207. }
  208. if (bOk == FALSE) {
  209. AttributeShowList.RemoveAll();
  210. }
  211. return bOk;
  212. }
  213. ResultSet*
  214. Statement::ExecuteSQL(
  215. IN HWND hdlg,
  216. IN OUT PTSTR pszSQL
  217. )
  218. /*++
  219. Statement::ExecuteSQL
  220. Desc: Executes the SQL string
  221. Params:
  222. IN HWND hdlg: The parent of any messagebox
  223. IN OUT PTSTR pszSQL: The SQL to be executed
  224. Return:
  225. The pointer to ResultSet of this Statement. This will NOT be NULL
  226. even if there are errors
  227. --*/
  228. {
  229. PNODELIST pInfix = NULL, pPostFix = NULL;
  230. BOOL bOk = FALSE;
  231. TCHAR* pszCurrent = NULL; // The current token
  232. BOOL bFromFound = FALSE;
  233. CSTRING strError;
  234. TCHAR* pszSQLCopy = NULL;
  235. K_SIZE k_size = lstrlen(pszSQL) + 1;
  236. pszSQLCopy = new TCHAR[k_size];
  237. if (pszSQLCopy == NULL) {
  238. MEM_ERR;
  239. goto End;
  240. }
  241. *pszSQLCopy = 0;
  242. SafeCpyN(pszSQLCopy, pszSQL, k_size);
  243. if (CSTRING::Trim(pszSQLCopy) == 0) {
  244. uErrorCode = ERROR_SELECT_NOTFOUND;
  245. goto End;
  246. }
  247. if (!CreateAttributesShowList(pszSQLCopy, &bFromFound)) {
  248. goto End;
  249. }
  250. resultset.SetShowList(&AttributeShowList);
  251. if (!bFromFound) {
  252. this->uErrorCode = ERROR_FROM_NOTFOUND;
  253. goto End;
  254. }
  255. if (!ProcessFrom(&pszCurrent)) {
  256. //
  257. // The error code has been set in the function
  258. //
  259. goto End;
  260. }
  261. //
  262. // We have got a 'where' and now we have to filter the results.
  263. //
  264. if (pszCurrent == NULL) {
  265. //
  266. // There was no where statement, this means all the entries have to be shown in FROM
  267. //
  268. pPostFix = new NODELIST;
  269. if (pPostFix == NULL) {
  270. MEM_ERR;
  271. goto End;
  272. }
  273. pPostFix->AddAtBeg(new NODE(DT_LITERAL_BOOL, TRUE));
  274. } else {
  275. //
  276. // We have a WHERE clause and we must filter the results now.
  277. //
  278. // Position the pointer just after WHERE.
  279. pszCurrent = pszCurrent + lstrlen(TEXT("WHERE"));
  280. pszCurrent++; // Get to the position where the delimiter was.
  281. pInfix = CreateInFix(pszSQL + (pszCurrent - pszSQLCopy));
  282. if (pInfix == NULL || uErrorCode != ERROR_NOERROR) {
  283. goto End;
  284. }
  285. pPostFix = CreatePostFix(pInfix);
  286. if (pPostFix == NULL || uErrorCode != ERROR_NOERROR) {
  287. goto End;
  288. }
  289. }
  290. bOk = EvaluatePostFix(pPostFix);
  291. End:
  292. if (pszSQLCopy) {
  293. delete[] pszSQLCopy;
  294. }
  295. if (pPostFix) {
  296. pPostFix->RemoveAll();
  297. delete pPostFix;
  298. pPostFix = NULL;
  299. }
  300. if (pInfix) {
  301. pInfix->RemoveAll();
  302. delete pInfix;
  303. pInfix = NULL;
  304. }
  305. if (uErrorCode != ERROR_NOERROR) {
  306. GetErrorMsg(strError);
  307. MessageBox(hdlg, (LPCTSTR)strError, g_szAppName, MB_ICONERROR);
  308. }
  309. return &resultset;
  310. }
  311. PNODELIST
  312. Statement::CreateInFix(
  313. IN OUT TCHAR* pszWhereString
  314. )
  315. /*++
  316. Statement::CreateInFix
  317. Desc: Parse the SQL string after the "where" to create the infix expression
  318. Params:
  319. IN OUT TCHAR* pszWhereString: SQL string After the WHERE ends
  320. Return:
  321. The Infix nodelist: If successful
  322. NULL: if Error
  323. --*/
  324. {
  325. TCHAR* pszCurrent = NULL; // The present token being checked
  326. TCHAR* pszTemp = NULL;
  327. PNODE pNode = NULL;
  328. PNODELIST pInfix = NULL;
  329. BOOL bOk = TRUE;
  330. UINT uIndex = 0, uSize = 0;
  331. INT iParenthesis = 0;
  332. BOOL bFound = FALSE;
  333. TCHAR* pszNewWhere = NULL;
  334. //
  335. // Now we parse the SQL string after the "where" to create the infix expression
  336. //
  337. if (pszWhereString == NULL || CSTRING::Trim(pszWhereString) == 0) {
  338. uErrorCode = ERROR_IMPROPERWHERE_FOUND;
  339. return NULL;
  340. }
  341. uSize = lstrlen(pszWhereString) * 2;
  342. pszNewWhere = new TCHAR[uSize];
  343. if (pszNewWhere == NULL) {
  344. MEM_ERR;
  345. return NULL;
  346. }
  347. *pszNewWhere = 0;
  348. pszCurrent = pszWhereString;
  349. //
  350. // Prefix
  351. //
  352. try{
  353. pInfix = new NODELIST;
  354. } catch(...) {
  355. pInfix = NULL;
  356. }
  357. if (pInfix == NULL) {
  358. MEM_ERR;
  359. if (pszNewWhere) {
  360. delete[] pszNewWhere;
  361. pszNewWhere = NULL;
  362. }
  363. return NULL;
  364. }
  365. //
  366. // Insert spaces as necessary so that it is easy to parse.
  367. //
  368. while (*pszWhereString && uIndex < uSize) {
  369. switch (*pszWhereString) {
  370. case TEXT(' '):
  371. if (uIndex < uSize) {
  372. pszNewWhere[uIndex++] = TEXT(' ');
  373. }
  374. while (pszWhereString && *pszWhereString == TEXT(' ')) {
  375. pszWhereString++;
  376. }
  377. break;
  378. case TEXT('\"'):
  379. pszNewWhere[uIndex++] = *pszWhereString;
  380. while (uIndex < uSize && *pszWhereString) {
  381. pszWhereString++;
  382. pszNewWhere[uIndex++] = *pszWhereString;
  383. if (*pszWhereString == 0 || *pszWhereString == TEXT('\"')) {
  384. break;
  385. }
  386. }
  387. if (*pszWhereString != TEXT('\"')) {
  388. uErrorCode = ERROR_STRING_NOT_TERMINATED;
  389. bOk = FALSE;
  390. break;
  391. } else {
  392. ++pszWhereString;
  393. }
  394. break;
  395. case TEXT('<'):
  396. pszNewWhere[uIndex++] = TEXT(' ');
  397. pszNewWhere[uIndex++] = *pszWhereString;
  398. ++pszWhereString;
  399. if (*pszWhereString == TEXT('>') || *pszWhereString == TEXT('=')) {
  400. pszNewWhere[uIndex++] = *pszWhereString;
  401. ++pszWhereString;
  402. }
  403. pszNewWhere[uIndex++] = TEXT(' ');
  404. break;
  405. case TEXT('>'):
  406. pszNewWhere[uIndex++] = TEXT(' ');
  407. pszNewWhere[uIndex++] = *pszWhereString;
  408. ++pszWhereString;
  409. if (*pszWhereString == TEXT('=')) {
  410. pszNewWhere[ uIndex++ ] = *pszWhereString;
  411. ++pszWhereString;
  412. }
  413. pszNewWhere[uIndex++] = TEXT(' ');
  414. break;
  415. case TEXT('='):
  416. case TEXT(')'):
  417. case TEXT('('):
  418. if (*pszWhereString == TEXT('(')) {
  419. ++iParenthesis;
  420. } else if (*pszWhereString == TEXT(')')) {
  421. --iParenthesis;
  422. }
  423. pszNewWhere[uIndex++] = TEXT(' ');
  424. pszNewWhere[uIndex++] = *pszWhereString;
  425. pszNewWhere[uIndex++] = TEXT(' ');
  426. pszWhereString++;
  427. break;
  428. default:
  429. pszNewWhere[uIndex++] = *pszWhereString;
  430. ++pszWhereString;
  431. break;
  432. }
  433. }
  434. if (iParenthesis != 0) {
  435. uErrorCode = ERROR_PARENTHESIS_COUNT;
  436. bOk = FALSE;
  437. goto End;
  438. }
  439. pszNewWhere[uIndex] = 0; // Do not forget the NULL at the end.
  440. if (bOk == FALSE) {
  441. goto End;
  442. }
  443. //
  444. // Now parse this string and create the Infix expression
  445. //
  446. pszCurrent = _tcstok(pszNewWhere, TEXT(" "));
  447. pNode = NULL;
  448. bFound = FALSE;
  449. while (pszCurrent) {
  450. if (*pszCurrent == TEXT('\"')) {
  451. //
  452. // String literal.
  453. //
  454. pszCurrent++; // Skip the leading "
  455. if (*(pszCurrent + lstrlen(pszCurrent) -1) != TEXT('\"') && *pszCurrent != 0) {
  456. //
  457. // _tcstok has put a '\0' at the end, it was a space earlier, make it a space
  458. // again so that we can tokenize on \"
  459. // e.g "hello world"
  460. //
  461. *(pszCurrent + lstrlen(pszCurrent)) = TEXT(' ');
  462. pszCurrent = _tcstok(pszCurrent, TEXT("\""));
  463. } else if (*pszCurrent == 0) {
  464. //
  465. // The character after the \" was a space earlier. This was made 0 by _tcstok
  466. // make it a space again so that we can tokenize on \"
  467. // e.g " hello"
  468. //
  469. *pszCurrent = TEXT(' ');
  470. pszCurrent = _tcstok(pszCurrent, TEXT("\""));
  471. } else {
  472. //
  473. // e.g. "hello"
  474. //
  475. *(pszCurrent + lstrlen(pszCurrent) -1) = 0; // Remove the triling \"
  476. }
  477. pNode = new NODE(DT_LITERAL_SZ, (LPARAM)pszCurrent);
  478. if (pNode == NULL) {
  479. MEM_ERR;
  480. break;
  481. }
  482. } else if (*pszCurrent == TEXT('(')) {
  483. pNode = new NODE(DT_LEFTPARANTHESES, 0);
  484. if (pNode == NULL) {
  485. MEM_ERR;
  486. break;
  487. }
  488. } else if (*pszCurrent == TEXT(')')) {
  489. pNode = new NODE(DT_RIGHTPARANTHESES, 0);
  490. if (pNode == NULL) {
  491. MEM_ERR;
  492. break;
  493. }
  494. } else {
  495. //
  496. // Now we have to handle the cases when the token can be a ATTR_M_* or a operator or
  497. // a integer literal or constant (TRUE/FALSE/NOBLOCK/BLOCK).
  498. //
  499. // First check if the token is a ATTR_M_*
  500. bFound = FALSE;
  501. for (UINT uIndexAttrMatch = 0; uIndexAttrMatch < ARRAYSIZE(AttributeMatchMapping); ++uIndexAttrMatch) {
  502. if (lstrcmpi(pszCurrent, AttributeMatchMapping[uIndexAttrMatch].szAttribute) == 0) {
  503. pNode = new NODE(DT_ATTRMATCH, AttributeMatchMapping[uIndexAttrMatch].attr);
  504. if (pNode == NULL) {
  505. MEM_ERR;
  506. break;
  507. }
  508. bFound = TRUE;
  509. break;
  510. }
  511. }
  512. if (bFound == FALSE) {
  513. //
  514. // Now check if that is an operator.
  515. //
  516. for (UINT uIndexOperator = 0;
  517. uIndexOperator < ARRAYSIZE(OperatorMapping);
  518. uIndexOperator++) {
  519. if (lstrcmpi(pszCurrent,
  520. OperatorMapping[uIndexOperator].szOperator) == 0) {
  521. pNode = new NODE;
  522. if (pNode == NULL) {
  523. MEM_ERR;
  524. break;
  525. }
  526. pNode->dtType = DT_OPERATOR;
  527. pNode->op.operator_type = OperatorMapping[uIndexOperator].op_type;
  528. pNode->op.uPrecedence = OperatorMapping[uIndexOperator].uPrecedence;
  529. bFound = TRUE;
  530. break;
  531. }
  532. }
  533. }
  534. if (bFound == FALSE) {
  535. //
  536. // Now it can only be a integer literal or one of the constants.
  537. //
  538. pNode = CheckAndAddConstants(pszCurrent);
  539. if (pNode == NULL) {
  540. BOOL bValid;
  541. INT iResult = Atoi(pszCurrent, &bValid);
  542. if (bValid) {
  543. pNode = new NODE(DT_LITERAL_INT, iResult);
  544. if (pNode == NULL) {
  545. MEM_ERR;
  546. bOk = FALSE;
  547. goto End;
  548. }
  549. } else {
  550. //
  551. // Some crap string was there, invalid SQL
  552. //
  553. uErrorCode = ERROR_IMPROPERWHERE_FOUND;
  554. bOk = FALSE;
  555. goto End;
  556. }
  557. }
  558. }
  559. }
  560. pInfix->AddAtEnd(pNode);
  561. pszCurrent = _tcstok(NULL, TEXT(" "));
  562. }
  563. End:
  564. if (bOk == FALSE) {
  565. if (pInfix) {
  566. pInfix->RemoveAll();
  567. pInfix = NULL;
  568. }
  569. }
  570. if (pszNewWhere) {
  571. delete[] pszNewWhere;
  572. pszNewWhere = NULL;
  573. }
  574. return pInfix;
  575. }
  576. PNODELIST
  577. Statement::CreatePostFix(
  578. IN OUT PNODELIST pInfix
  579. )
  580. /*++
  581. Statement::CreatePostFix
  582. Desc: Creates a post fix nodelist from infix nodelist
  583. Params:
  584. IN PNODELIST pInfix: The infix nodelist
  585. Return:
  586. The PostFix Nodelist: If Success
  587. NULL: If error
  588. Algo: Suppose INFIX is a SQL expression in infix notation. This algorith finds
  589. the equivalent postfix notation in POSTFIX. STACK is a user defined stack data
  590. structure
  591. 1. Push '(' into STACK and add ')' to the end of INFIX
  592. 2. Scan INFIX from left to right and repeat steps 3 tp 6 for each element
  593. of INFIX untill the STACK becomes empty
  594. 3. If an operand is encountered, add it to POSTFIX
  595. 4. If a left parenthesis is encountered, push it onto STACK
  596. 5. If an operator $ is encountered then:
  597. a) Repeatedly pop from STACK and add to POSTFIX each operator
  598. (from the top of the STACK) which has the same precedence as or
  599. higher than $
  600. b) Add $ to STACK
  601. 6. If a right parenthesis is encountered, then:
  602. a) Repeatedly pop from STACK and add to POSTFIX each operator (on the top of STACK),
  603. untill a left parenthesis is encountered
  604. b) Remove the left parenthesis. (Do not add the left parenthesis to POSTFIX)
  605. 7. Exit
  606. Notes: This routine, uses the nodes of the infix nodelist to create the post fix
  607. nodelist, so the infix nodelist effectively gets destroyed
  608. --*/
  609. {
  610. BOOL bOk = TRUE;
  611. PNODELIST pPostFix = NULL;
  612. PNODE pNodeTemp = NULL, pNodeInfix = NULL;
  613. NODELIST Stack;
  614. if (pInfix == NULL) {
  615. assert(FALSE);
  616. Dbg(dlError, "CreatePostFix", "pInfix == NULL");
  617. bOk = FALSE;
  618. goto End;
  619. }
  620. pPostFix = new NODELIST;
  621. if (pPostFix == NULL) {
  622. bOk = FALSE;
  623. goto End;
  624. }
  625. pNodeTemp = new NODE;
  626. if (pNodeTemp == NULL) {
  627. bOk = FALSE;
  628. goto End;
  629. }
  630. pNodeTemp->dtType = DT_LEFTPARANTHESES;
  631. //
  632. // Push a initial left parenthesis in the stack.
  633. //
  634. Stack.Push(pNodeTemp);
  635. //
  636. // Add a right parenthesis to the end of pInfix
  637. //
  638. pNodeTemp = new NODE;
  639. if (pNodeTemp == NULL) {
  640. bOk = FALSE;
  641. goto End;
  642. }
  643. pNodeTemp->dtType = DT_RIGHTPARANTHESES;
  644. pInfix->AddAtEnd(pNodeTemp);
  645. while (pNodeInfix = pInfix->Pop()) {
  646. switch (pNodeInfix->dtType) {
  647. case DT_LEFTPARANTHESES:
  648. Stack.Push(pNodeInfix);
  649. break;
  650. case DT_OPERATOR:
  651. //
  652. // Repeatedly pop from stack and add to pPostFix each operator (on the top of stack)
  653. // that has the same precedence as or higher than the present operator
  654. //
  655. while (Stack.m_pHead &&
  656. Stack.m_pHead->dtType == DT_OPERATOR &&
  657. Stack.m_pHead->op.uPrecedence >= pNodeInfix->op.uPrecedence) {
  658. pNodeTemp = Stack.Pop();
  659. if (pNodeTemp == NULL) {
  660. uErrorCode = ERROR_IMPROPERWHERE_FOUND;
  661. bOk = FALSE;
  662. goto End;
  663. } else {
  664. pPostFix->AddAtEnd(pNodeTemp);
  665. }
  666. }// while
  667. Stack.Push(pNodeInfix);
  668. break;
  669. case DT_RIGHTPARANTHESES:
  670. //
  671. // Repeatedly pop from the stack and add to pPosFix each operator (on the top of STACK)
  672. // untill a left paranthesis is encountered.
  673. //
  674. // Remove the left parenthesis, do not add it to pPostFix
  675. //
  676. while (Stack.m_pHead &&
  677. Stack.m_pHead->dtType == DT_OPERATOR) {
  678. pNodeTemp = Stack.Pop();
  679. pPostFix->AddAtEnd(pNodeTemp);
  680. }
  681. if (Stack.m_pHead && Stack.m_pHead->dtType != DT_LEFTPARANTHESES) {
  682. //
  683. // Inavalid SQL
  684. //
  685. uErrorCode = ERROR_IMPROPERWHERE_FOUND;
  686. bOk = FALSE;
  687. goto End;
  688. }
  689. pNodeTemp = Stack.Pop(); // This is the left parenthesis
  690. if (pNodeTemp) {
  691. delete pNodeTemp;
  692. }
  693. if (pNodeInfix) {
  694. delete pNodeInfix; // Delete the right parenthesis in the infix expression.
  695. }
  696. break;
  697. case DT_UNKNOWN:
  698. assert(FALSE);
  699. bOk = FALSE;
  700. goto End;
  701. break;
  702. default:
  703. //
  704. // The operands
  705. //
  706. pPostFix->AddAtEnd(pNodeInfix);
  707. break;
  708. }
  709. }
  710. End:
  711. if (!bOk && pPostFix) {
  712. pPostFix->RemoveAll();
  713. pPostFix = NULL;
  714. }
  715. return pPostFix;
  716. }
  717. BOOL
  718. Statement::EvaluatePostFix(
  719. IN PNODELIST pPostFix
  720. )
  721. /*++
  722. Statement::EvaluatePostFix
  723. Desc: This function takes the post-fix expression and then adds only
  724. the entries that match the expression to the result-set.
  725. Params:
  726. IN PNODELIST pPostFix: The postfix expression to be actually executed to populate
  727. the result set
  728. Return:
  729. TRUE: The function executed successfully
  730. FALSE: There was some error
  731. --*/
  732. {
  733. PDATABASE pDataBase;
  734. PDBENTRY pEntry, pApp;
  735. BOOL bOk = FALSE;
  736. //
  737. // For the global database
  738. //
  739. if (m_uCheckDB & DATABASE_TYPE_GLOBAL) {
  740. pDataBase = &GlobalDataBase;
  741. if (g_bMainAppExpanded == FALSE) {
  742. SetStatus(GetDlgItem(m_hdlg, IDC_STATUSBAR), IDS_LOADINGMAIN);
  743. SetCursor(LoadCursor(NULL, IDC_WAIT));
  744. ShowMainEntries(g_hDlg);
  745. SetCursor(LoadCursor(NULL, IDC_ARROW));
  746. SetStatus(GetDlgItem(m_hdlg, IDC_STATUSBAR), TEXT(""));
  747. }
  748. pApp = pEntry = pDataBase ? pDataBase->pEntries : NULL;
  749. while (pEntry) {
  750. FilterAndAddToResultSet(pDataBase, pEntry, pPostFix);
  751. if (uErrorCode) {
  752. goto End;
  753. }
  754. pEntry = pEntry->pSameAppExe;
  755. if (pEntry == NULL) {
  756. pEntry = pApp = pApp->pNext;
  757. }
  758. }
  759. }
  760. //
  761. // For the installed database
  762. //
  763. if (m_uCheckDB & DATABASE_TYPE_INSTALLED) {
  764. //
  765. // We need to protect the access to the installed database data, because
  766. // that can get updated if some database is installed or uninstalled. The updating
  767. // will take place in a different (the main) thread and this will make the data
  768. // structure inconsistent
  769. //
  770. EnterCriticalSection(&g_csInstalledList);
  771. pDataBase = InstalledDataBaseList.pDataBaseHead;
  772. while (pDataBase) {
  773. pApp = pEntry = (pDataBase) ? pDataBase->pEntries : NULL;
  774. while (pEntry) {
  775. FilterAndAddToResultSet(pDataBase, pEntry, pPostFix);
  776. if (uErrorCode) {
  777. LeaveCriticalSection(&g_csInstalledList);
  778. goto End;
  779. }
  780. pEntry = pEntry->pSameAppExe;
  781. if (pEntry == NULL) {
  782. pEntry = pApp = pApp->pNext;
  783. }
  784. }
  785. pDataBase = pDataBase->pNext;
  786. }
  787. LeaveCriticalSection(&g_csInstalledList);
  788. }
  789. //
  790. // For the custom databases
  791. //
  792. if (m_uCheckDB & DATABASE_TYPE_WORKING) {
  793. pDataBase = DataBaseList.pDataBaseHead;
  794. while (pDataBase) {
  795. pApp = pEntry = pDataBase ? pDataBase->pEntries : NULL;
  796. while (pEntry) {
  797. FilterAndAddToResultSet(pDataBase, pEntry, pPostFix);
  798. if (uErrorCode) {
  799. goto End;
  800. }
  801. pEntry = pEntry->pSameAppExe;
  802. if (pEntry == NULL) {
  803. pEntry = pApp = pApp->pNext;
  804. }
  805. }
  806. pDataBase = pDataBase->pNext;
  807. }
  808. }
  809. bOk = TRUE;
  810. End:
  811. return bOk;
  812. }
  813. BOOL
  814. Statement::FilterAndAddToResultSet(
  815. IN PDATABASE pDatabase,
  816. IN PDBENTRY pEntry,
  817. IN PNODELIST pPostfix
  818. )
  819. {
  820. /*++
  821. Statement::FilterAndAddToResultSet
  822. Desc: This function checks if the pEntry in database pDatabase actually
  823. satisfies pPostFix if it does, then it adds the entry into the resultset.
  824. Params:
  825. IN PDATABASE pDatabase: The database in which pEntry resides
  826. IN PDBENTRY pEntry: The entry that we want to check whether it satisfies pPostfix
  827. IN PNODELIST pPostfix: The postfix nodelist
  828. Return:
  829. TRUE: The pEntry in pDatabase satisfies the post-fix expression pPostfix
  830. FALSE: Otherwise.
  831. Algo: Algorithm to find the result of a SQL expression in POSTFIX. The result
  832. is calculated for attribute values of PDBENTRY pEntry that lives in PDATABASE pDatabase
  833. 1. While there are some elements in POSTFIX do
  834. 1.1 If an operand is encountered, put it on STACK
  835. 1.2 If an operator $ is encountered then:
  836. a) Remove the top twp elements of STACK, where A is the top
  837. element and B is the next to top element
  838. b) Evaluate B $ A
  839. c) Place the result of (b) on STACK
  840. 2. The value of the expression is the value that is on top of the stack
  841. Notes: We need to make a copy of pPostFix and work on that.
  842. --*/
  843. PNODE pNodeTemp, pNodeOperandLeft, pNodeOperandRight, pNodeResult;
  844. BOOL bResult = FALSE;
  845. NODELIST nlCopyPostFix;
  846. NODELIST Stack;
  847. PNODE pNodePostfixHead = pPostfix->m_pHead;
  848. pNodeResult = pNodeTemp = pNodeOperandLeft = pNodeOperandRight = NULL;
  849. //
  850. // Make a copy of the post-fix expression. While evaluating the expression the
  851. // postix expression gets modified, so we have to work on a copy as we
  852. // need the original postfix expression to persist till we have checked
  853. // all the entries.
  854. //
  855. while (pNodePostfixHead) {
  856. pNodeTemp = new NODE();
  857. if (pNodeTemp == NULL) {
  858. MEM_ERR;
  859. bResult = FALSE;
  860. goto End;
  861. }
  862. pNodeTemp->dtType = pNodePostfixHead->dtType;
  863. switch (pNodePostfixHead->dtType) {
  864. case DT_LITERAL_BOOL:
  865. pNodeTemp->bData = pNodePostfixHead->bData;
  866. break;
  867. case DT_LITERAL_INT:
  868. pNodeTemp->iData = pNodePostfixHead->iData;
  869. break;
  870. case DT_LITERAL_SZ:
  871. pNodeTemp->SetString(pNodePostfixHead->szString);
  872. break;
  873. case DT_OPERATOR:
  874. pNodeTemp->op.operator_type = pNodePostfixHead->op.operator_type;
  875. pNodeTemp->op.uPrecedence = pNodePostfixHead->op.uPrecedence;
  876. break;
  877. case DT_ATTRMATCH:
  878. pNodeTemp->attrMatch = pNodePostfixHead->attrMatch;
  879. break;
  880. }
  881. nlCopyPostFix.AddAtEnd(pNodeTemp);
  882. pNodePostfixHead = pNodePostfixHead->pNext;
  883. }
  884. while (pNodeTemp = nlCopyPostFix.Pop()) {
  885. if (pNodeTemp->dtType == DT_OPERATOR) {
  886. pNodeOperandRight = Stack.Pop();
  887. pNodeOperandLeft = Stack.Pop();
  888. if (pNodeOperandRight == NULL || pNodeOperandLeft == NULL) {
  889. uErrorCode = ERROR_WRONGNUMBER_OPERANDS;
  890. bResult = FALSE;
  891. goto End;
  892. }
  893. pNodeResult = Evaluate(pDatabase,
  894. pEntry,
  895. pNodeOperandLeft,
  896. pNodeOperandRight,
  897. pNodeTemp);
  898. if (pNodeResult == NULL) {
  899. bResult = FALSE;
  900. goto End;
  901. }
  902. Stack.Push(pNodeResult);
  903. if (pNodeOperandLeft) {
  904. delete pNodeOperandLeft;
  905. }
  906. if (pNodeOperandRight) {
  907. delete pNodeOperandRight;
  908. }
  909. delete pNodeTemp;
  910. } else {
  911. Stack.Push(pNodeTemp);
  912. }
  913. }
  914. pNodeTemp = Stack.Pop();
  915. if (pNodeTemp == NULL || pNodeTemp->dtType != DT_LITERAL_BOOL) {
  916. uErrorCode = ERROR_IMPROPERWHERE_FOUND;
  917. bResult = FALSE;
  918. goto End;
  919. }
  920. bResult = pNodeTemp->bData;
  921. if (pNodeTemp) {
  922. delete pNodeTemp;
  923. }
  924. if (bResult) {
  925. //
  926. // Entry satisfies the postfix
  927. //
  928. resultset.AddAtLast(new RESULT_ITEM(pDatabase, pEntry));
  929. }
  930. End:
  931. // Stack and nlCopyPostFix contents are removed through their desctructors.
  932. return bResult;
  933. }
  934. PNODE
  935. Statement::Evaluate(
  936. IN PDATABASE pDatabase,
  937. IN PDBENTRY pEntry,
  938. IN PNODE pOperandLeft,
  939. IN PNODE pOperandRight,
  940. IN PNODE pOperator
  941. )
  942. /*++
  943. Statement::Evaluate
  944. Desc: This function evaluates a binary expression
  945. Params:
  946. IN PDATABASE pDatabase: The database in which pEntry resides
  947. IN PDBENTRY pEntry: The entry that is being currently checked, to
  948. see if it satisfies the post fix
  949. IN PNODE pOperandLeft: The left operand
  950. IN PNODE pOperandRight: The right operand
  951. IN PNODE pOperator: The operator to be applied to the above operands
  952. Return: The result of applying the operator on the left and right operands
  953. --*/
  954. {
  955. BOOL bOk = TRUE;
  956. PNODE pNodeResult = new NODE;
  957. if (pNodeResult == NULL) {
  958. MEM_ERR;
  959. return NULL;
  960. }
  961. pNodeResult->dtType = DT_LITERAL_BOOL;
  962. if (pOperandLeft == NULL
  963. || pOperandRight == NULL
  964. || pDatabase == NULL
  965. || pEntry == NULL
  966. || pOperator == NULL) {
  967. bOk = FALSE;
  968. assert(FALSE);
  969. Dbg(dlError, "Statement::Evaluate", "Invalid arguments to function");
  970. goto End;
  971. }
  972. //
  973. // We will have to set the values appropriately for the attributes so that we can
  974. // apply the operator on them
  975. //
  976. if (!SetValuesForOperands(pDatabase, pEntry, pOperandLeft)) {
  977. bOk = FALSE;
  978. goto End;
  979. }
  980. if (!SetValuesForOperands(pDatabase, pEntry, pOperandRight)) {
  981. bOk = FALSE;
  982. goto End;
  983. }
  984. //
  985. // Now both the left and the right operands have proper values (except operands with ATTR_M_LAYER/SHIMFLAG/PATCH/MATCHINGFILE _NAME type)
  986. //
  987. switch (pOperator->op.operator_type) {
  988. case OPER_AND:
  989. //
  990. // Both operands should be boolean
  991. //
  992. if (pOperandLeft->dtType != DT_LITERAL_BOOL || pOperandRight->dtType != DT_LITERAL_BOOL) {
  993. uErrorCode = ERROR_INVALID_AND_OPERANDS;
  994. bOk = FALSE;
  995. goto End;
  996. } else {
  997. pNodeResult->bData = pOperandLeft->bData && pOperandRight->bData;
  998. }
  999. break;
  1000. case OPER_OR:
  1001. //
  1002. // Both operands should be boolean
  1003. //
  1004. if (pOperandLeft->dtType != DT_LITERAL_BOOL || pOperandRight->dtType != DT_LITERAL_BOOL) {
  1005. uErrorCode = ERROR_INVALID_OR_OPERANDS;
  1006. bOk = FALSE;
  1007. goto End;
  1008. } else {
  1009. pNodeResult->bData = pOperandLeft->bData || pOperandRight->bData;
  1010. }
  1011. break;
  1012. case OPER_EQUAL:
  1013. CHECK_OPERAND_TYPE(bOk,End);
  1014. switch (pOperandLeft->dtType) {
  1015. case DT_LITERAL_BOOL:
  1016. pNodeResult->bData = pOperandLeft->bData == pOperandRight->bData;
  1017. break;
  1018. case DT_LITERAL_INT:
  1019. pNodeResult->bData = pOperandLeft->iData == pOperandRight->iData;
  1020. break;
  1021. case DT_LITERAL_SZ:
  1022. pNodeResult->bData = CheckIfContains(pOperandLeft->szString, pOperandRight->szString);
  1023. break;
  1024. }
  1025. break;
  1026. case OPER_GE:
  1027. CHECK_OPERAND_TYPE(bOk,End);
  1028. switch (pOperandLeft->dtType) {
  1029. case DT_LITERAL_BOOL:
  1030. uErrorCode = ERROR_INVALID_GE_OPERANDS;
  1031. bOk = FALSE;
  1032. goto End;
  1033. break;
  1034. case DT_LITERAL_INT:
  1035. pNodeResult->bData = pOperandLeft->iData >= pOperandRight->iData;
  1036. break;
  1037. case DT_LITERAL_SZ:
  1038. pNodeResult->bData = lstrcmpi(pOperandLeft->szString, pOperandRight->szString) >= 0 ? TRUE : FALSE;
  1039. break;
  1040. }
  1041. break;
  1042. case OPER_GT:
  1043. CHECK_OPERAND_TYPE(bOk,End);
  1044. switch (pOperandLeft->dtType) {
  1045. case DT_LITERAL_BOOL:
  1046. uErrorCode = ERROR_INVALID_GT_OPERANDS;
  1047. bOk = FALSE;
  1048. goto End;
  1049. break;
  1050. case DT_LITERAL_INT:
  1051. pNodeResult->bData = pOperandLeft->iData > pOperandRight->iData;
  1052. break;
  1053. case DT_LITERAL_SZ:
  1054. pNodeResult->bData = lstrcmpi(pOperandLeft->szString, pOperandRight->szString) > 0 ? TRUE : FALSE;
  1055. break;
  1056. }
  1057. break;
  1058. case OPER_LE:
  1059. CHECK_OPERAND_TYPE(bOk,End);
  1060. switch (pOperandLeft->dtType) {
  1061. case DT_LITERAL_BOOL:
  1062. uErrorCode = ERROR_INVALID_LE_OPERANDS;
  1063. bOk = FALSE;
  1064. goto End;
  1065. break;
  1066. case DT_LITERAL_INT:
  1067. pNodeResult->bData = pOperandLeft->iData <= pOperandRight->iData;
  1068. break;
  1069. case DT_LITERAL_SZ:
  1070. pNodeResult->bData = lstrcmpi(pOperandLeft->szString, pOperandRight->szString) <= 0 ? TRUE : FALSE;
  1071. break;
  1072. }
  1073. break;
  1074. case OPER_LT:
  1075. CHECK_OPERAND_TYPE(bOk,End);
  1076. switch (pOperandLeft->dtType) {
  1077. case DT_LITERAL_BOOL:
  1078. uErrorCode = ERROR_INVALID_LE_OPERANDS;
  1079. bOk = FALSE;
  1080. goto End;
  1081. break;
  1082. case DT_LITERAL_INT:
  1083. pNodeResult->bData = pOperandLeft->iData < pOperandRight->iData;
  1084. break;
  1085. case DT_LITERAL_SZ:
  1086. pNodeResult->bData = lstrcmpi(pOperandLeft->szString, pOperandRight->szString) < 0 ? TRUE : FALSE;
  1087. break;
  1088. }
  1089. break;
  1090. case OPER_NE:
  1091. CHECK_OPERAND_TYPE(bOk,End);
  1092. switch (pOperandLeft->dtType) {
  1093. case DT_LITERAL_BOOL:
  1094. pNodeResult->bData = pOperandLeft->bData != pOperandRight->bData;
  1095. break;
  1096. case DT_LITERAL_INT:
  1097. pNodeResult->bData = pOperandLeft->iData != pOperandRight->iData;
  1098. break;
  1099. case DT_LITERAL_SZ:
  1100. pNodeResult->bData = !CheckIfContains(pOperandLeft->szString, pOperandRight->szString);
  1101. break;
  1102. }
  1103. break;
  1104. case OPER_CONTAINS:
  1105. //
  1106. // Valid only for string operands. Order of operands is important
  1107. //
  1108. if (pOperandLeft == NULL
  1109. || pOperandRight == NULL
  1110. || pOperandLeft->dtType != DT_LITERAL_SZ
  1111. || pOperandRight->dtType != DT_LITERAL_SZ) {
  1112. uErrorCode = ERROR_INVALID_CONTAINS_OPERANDS;
  1113. bOk = FALSE;
  1114. goto End;
  1115. }
  1116. pNodeResult->bData = CheckIfContains(pOperandLeft->szString,
  1117. pOperandRight->szString);
  1118. break;
  1119. case OPER_HAS:
  1120. //
  1121. // This operator is valid only for multi-valued attributes of the entry. Like layers, shims, pathces
  1122. // This operator is used in this context: "Which entry has the layer Win95"
  1123. //
  1124. if (pOperandRight->dtType == DT_LITERAL_SZ
  1125. && pOperandLeft->dtType == DT_ATTRMATCH
  1126. && (pOperandLeft->attrMatch == ATTR_M_LAYER_NAME
  1127. || pOperandLeft->attrMatch == ATTR_M_MATCHFILE_NAME
  1128. || pOperandLeft->attrMatch == ATTR_M_PATCH_NAME
  1129. || pOperandLeft->attrMatch == ATTR_M_SHIM_NAME)) {
  1130. pNodeResult->bData = ApplyHasOperator(pEntry,
  1131. pOperandLeft,
  1132. pOperandRight->szString);
  1133. } else {
  1134. uErrorCode = ERROR_INVALID_HAS_OPERANDS;
  1135. goto End;
  1136. }
  1137. break;
  1138. }
  1139. End:
  1140. if (!bOk) {
  1141. if (pNodeResult) {
  1142. delete pNodeResult;
  1143. pNodeResult = NULL;
  1144. }
  1145. }
  1146. return pNodeResult;
  1147. }
  1148. void
  1149. Statement::SelectAll(
  1150. void
  1151. )
  1152. {
  1153. /*++
  1154. Statement::SelectAll
  1155. Desc: This function is called when we have encountered a '*' while creating
  1156. the AttributeShowList. As a result of this all the attributes in
  1157. AttributeMatchMapping have to be added to the AttributeShowList
  1158. Notes: If this function is called twice or more for a SQL expression,
  1159. say we have SELECT *,*,* all the attributes will still be shown just once.
  1160. --*/
  1161. PNODE pNode = NULL;
  1162. AttributeShowList.RemoveAll();
  1163. for (UINT uIndex = 0; uIndex < ARRAYSIZE(AttributeShowMapping); ++uIndex) {
  1164. pNode = new NODE(DT_ATTRSHOW, AttributeShowMapping[uIndex].attr);
  1165. if (pNode == NULL) {
  1166. MEM_ERR;
  1167. break;
  1168. }
  1169. AttributeShowList.AddAtEnd(pNode);
  1170. }
  1171. }
  1172. BOOL
  1173. Statement::ProcessFrom(
  1174. OUT TCHAR** ppszWhere
  1175. )
  1176. /*++
  1177. Statement::ProcessFrom
  1178. Desc: This function starts immeditely from where FROM ends in the SQL
  1179. and then it sets which databases system, installed or custom,
  1180. (There can be combinations as well) have to be checked for
  1181. entries that match the where condition.
  1182. Params:
  1183. OUT TCHAR** ppszWhere: The pointer to WHERE in the SQL
  1184. Return:
  1185. FALSE: If the tokens after FROM are invalid
  1186. TRUE: Otherwise
  1187. Warn: We should NOT have called _tcstok after getting the AttributeShowList
  1188. using [ CreateAttributesShowList() ] and before we call this routine.
  1189. This routine assumes that the static pointer of _tcstok is poised
  1190. just after FROM in the SQL
  1191. --*/
  1192. {
  1193. TCHAR* pszCurrentToken = NULL;
  1194. BOOL bOk = TRUE, bFound = FALSE;
  1195. if (ppszWhere == NULL) {
  1196. assert(FALSE);
  1197. return FALSE;
  1198. }
  1199. *ppszWhere = NULL;
  1200. pszCurrentToken = _tcstok(NULL, TEXT(" ,"));
  1201. if (pszCurrentToken == NULL) {
  1202. bOk = FALSE;
  1203. uErrorCode = ERROR_INVALID_DBTYPE_INFROM;
  1204. goto End;
  1205. }
  1206. m_uCheckDB = 0;
  1207. while (pszCurrentToken) {
  1208. bFound = FALSE;
  1209. for (UINT uIndex = 0; uIndex < ARRAYSIZE(DatabasesMapping); ++uIndex) {
  1210. if (lstrcmpi(DatabasesMapping[uIndex].szDatabaseType, pszCurrentToken) == 0) {
  1211. m_uCheckDB |= DatabasesMapping[uIndex].dbtype;
  1212. bFound = TRUE;
  1213. break;
  1214. }
  1215. }
  1216. if (bFound == FALSE) {
  1217. if (lstrcmpi(TEXT("WHERE"), pszCurrentToken) == 0) {
  1218. *ppszWhere = pszCurrentToken;
  1219. goto End;
  1220. //
  1221. // We do not change the bOk here. If even one valid db type has been found
  1222. // bOk will remain true unless we find a invalid db type.
  1223. //
  1224. }
  1225. //
  1226. // Some crap string, not a valid db-type
  1227. //
  1228. uErrorCode = ERROR_INVALID_DBTYPE_INFROM;
  1229. bOk = FALSE;
  1230. goto End;
  1231. }
  1232. pszCurrentToken = _tcstok(NULL, TEXT(" ,"));
  1233. }
  1234. End:
  1235. if (m_uCheckDB == 0) {
  1236. uErrorCode = ERROR_INVALID_DBTYPE_INFROM;
  1237. bOk = FALSE;
  1238. }
  1239. return bOk;
  1240. }
  1241. void
  1242. GetFixesAppliedToEntry(
  1243. IN PDBENTRY pEntry,
  1244. OUT CSTRING& strFixes
  1245. )
  1246. /*++
  1247. GetShimsAppliedToEntry
  1248. Desc: Makes a string of all the shims and flags that are applied to an entry
  1249. and assigns that to strFixes
  1250. Params:
  1251. IN PDBENTRY pEntry: The entry whose shims and flags we want to get
  1252. OUT CSTRING strTemp: The string in which the result will be stored
  1253. Return:
  1254. void
  1255. --*/
  1256. {
  1257. PSHIM_FIX_LIST psflIndex = NULL;
  1258. PFLAG_FIX_LIST pfflIndex = NULL;
  1259. CSTRING strTemp;
  1260. if (pEntry == NULL) {
  1261. assert(FALSE);
  1262. goto End;
  1263. }
  1264. psflIndex = pEntry->pFirstShim;
  1265. strFixes = TEXT("");
  1266. //
  1267. // Loop through all the shims for this entry and add their names to the string
  1268. //
  1269. while (psflIndex) {
  1270. if (psflIndex->pShimFix) {
  1271. strTemp.Sprintf(TEXT("%s, "), (LPCTSTR)psflIndex->pShimFix->strName);
  1272. strFixes.Strcat(strTemp);
  1273. } else {
  1274. assert(FALSE);
  1275. }
  1276. psflIndex = psflIndex->pNext;
  1277. }
  1278. pfflIndex = pEntry->pFirstFlag;
  1279. //
  1280. // Loop through all the flags for this entry and add their names to the string
  1281. //
  1282. while (pfflIndex) {
  1283. if (pfflIndex->pFlagFix) {
  1284. strTemp.Sprintf(TEXT("%s, "), (LPCTSTR)pfflIndex->pFlagFix->strName);
  1285. strFixes.Strcat(strTemp);
  1286. } else {
  1287. assert(FALSE);
  1288. }
  1289. pfflIndex = pfflIndex->pNext;
  1290. }
  1291. //
  1292. // Remove the last ,\s pair. (\s means a space character);
  1293. //
  1294. strFixes.SetChar(strFixes.Length() - 2, 0);
  1295. End:
  1296. return;
  1297. }
  1298. void
  1299. GetLayersAppliedToEntry(
  1300. IN PDBENTRY pEntry,
  1301. OUT CSTRING& strFixes
  1302. )
  1303. /*++
  1304. GetLayersAppliedToEntry
  1305. Desc: Makes a string of all the layers that are applied to an entry
  1306. and assigns that to strFixes
  1307. Params:
  1308. IN PDBENTRY pEntry: The entry whose shims and flags we want to get
  1309. OUT CSTRING strTemp: The string in which the result will be stored
  1310. Return:
  1311. void
  1312. --*/
  1313. {
  1314. PLAYER_FIX_LIST plflIndex = NULL;
  1315. CSTRING strTemp;
  1316. if (pEntry == NULL) {
  1317. assert(FALSE);
  1318. goto End;
  1319. }
  1320. plflIndex = pEntry->pFirstLayer;
  1321. strFixes = TEXT("");
  1322. //
  1323. // Loop through all the layers for this entry and add their names to the string
  1324. //
  1325. while (plflIndex) {
  1326. if (plflIndex->pLayerFix) {
  1327. strTemp.Sprintf(TEXT("%s, "), (LPCTSTR)plflIndex->pLayerFix->strName);
  1328. strFixes.Strcat(strTemp);
  1329. } else {
  1330. assert(FALSE);
  1331. }
  1332. plflIndex = plflIndex->pNext;
  1333. }
  1334. //
  1335. // Remove the last ,\s pair. (\s means a space character);
  1336. //
  1337. strFixes.SetChar(strFixes.Length() - 2, 0);
  1338. End:
  1339. return;
  1340. }
  1341. void
  1342. GetPatchesAppliedToEntry(
  1343. IN PDBENTRY pEntry,
  1344. OUT CSTRING& strFixes
  1345. )
  1346. /*++
  1347. GetPatchesAppliedToEntry
  1348. Desc: Makes a string of all the patches that are applied to an entry
  1349. and assigns that to strFixes
  1350. Params:
  1351. IN PDBENTRY pEntry: The entry whose shims and flags we want to get
  1352. OUT CSTRING strTemp: The string in which the result will be stored
  1353. Return:
  1354. void
  1355. --*/
  1356. {
  1357. PPATCH_FIX_LIST ppflIndex = NULL;
  1358. CSTRING strTemp;
  1359. if (pEntry == NULL) {
  1360. assert(FALSE);
  1361. goto End;
  1362. }
  1363. ppflIndex = pEntry->pFirstPatch;
  1364. strFixes = TEXT("");
  1365. //
  1366. // Loop through all the patches for this entry and add their names to the string
  1367. //
  1368. while (ppflIndex) {
  1369. if (ppflIndex->pPatchFix) {
  1370. strTemp.Sprintf(TEXT("%s, "), (LPCTSTR)ppflIndex->pPatchFix->strName);
  1371. strFixes.Strcat(strTemp);
  1372. } else {
  1373. assert(FALSE);
  1374. }
  1375. ppflIndex = ppflIndex->pNext;
  1376. }
  1377. //
  1378. // Remove the last ,\s pair. (\s means a space character);
  1379. //
  1380. strFixes.SetChar(strFixes.Length() - 2, 0);
  1381. End:
  1382. return;
  1383. }
  1384. void
  1385. GetMatchingFilesForEntry(
  1386. IN PDBENTRY pEntry,
  1387. OUT CSTRING& strMatchingFiles
  1388. )
  1389. /*++
  1390. GetMatchingFilesForEntry
  1391. Desc: Makes a string of all the matching files that are used for identifying
  1392. this entry and assigns that to strMatchingFiles
  1393. Params:
  1394. IN PDBENTRY pEntry: The entry whose shims and flags we want to get
  1395. OUT CSTRING strTemp: The string in which the result will be stored
  1396. Return:
  1397. void
  1398. --*/
  1399. {
  1400. PMATCHINGFILE pMatchIndex = NULL;
  1401. CSTRING strTemp;
  1402. if (pEntry == NULL) {
  1403. assert(FALSE);
  1404. goto End;
  1405. }
  1406. pMatchIndex = pEntry->pFirstMatchingFile;
  1407. strMatchingFiles = TEXT("");
  1408. //
  1409. // Loop through all the matching files for this entry and add their names to the string
  1410. //
  1411. while (pMatchIndex) {
  1412. if (pMatchIndex->strMatchName == TEXT("*")) {
  1413. //
  1414. // The program being fixed. Get its file name
  1415. //
  1416. strTemp.Sprintf(TEXT("%s, "), (LPCTSTR)pEntry->strExeName);
  1417. } else {
  1418. strTemp.Sprintf(TEXT("%s, "), (LPCTSTR)pMatchIndex->strMatchName);
  1419. }
  1420. strMatchingFiles.Strcat(strTemp);
  1421. pMatchIndex = pMatchIndex->pNext;
  1422. }
  1423. //
  1424. // Remove the last ,\s pair. (\s means a space character);
  1425. //
  1426. strMatchingFiles.SetChar(strMatchingFiles.Length() - 2, 0);
  1427. End:
  1428. return;
  1429. }
  1430. BOOL
  1431. SetValuesForOperands(
  1432. IN PDATABASE pDatabase,
  1433. IN PDBENTRY pEntry,
  1434. IN OUT PNODE pOperand
  1435. )
  1436. /*++
  1437. SetValuesForOperands
  1438. Desc: Sets the values for the various attributes after getting them from the
  1439. database or the entry. Sets the values in pOperand, also sets the type in
  1440. pOperand
  1441. Params:
  1442. IN PDATABASE pDatabase: The entry for which we want to get the values
  1443. of some of the attributes resides in this database
  1444. IN PDBENTRY pEntry: The entry for which we want to get the values
  1445. of some of the attributes
  1446. IN OUT PNODE pOperand: The value and the type of the value will be stored
  1447. here
  1448. Return:
  1449. TRUE: If the value has been successfully oobtained and set
  1450. FALSE: Otherwise
  1451. --*/
  1452. {
  1453. CSTRING strTemp;
  1454. if (!pOperand || !pDatabase || !pOperand) {
  1455. assert(FALSE);
  1456. return FALSE;
  1457. }
  1458. if (pOperand->dtType == DT_ATTRMATCH || pOperand->dtType == DT_ATTRSHOW) {
  1459. switch (pOperand->attrMatch) {
  1460. case ATTR_S_APP_NAME:
  1461. case ATTR_M_APP_NAME:
  1462. pOperand->SetString(pEntry->strAppName);
  1463. break;
  1464. case ATTR_S_DATABASE_GUID:
  1465. case ATTR_M_DATABASE_GUID:
  1466. pOperand->SetString(pDatabase->szGUID);
  1467. break;
  1468. case ATTR_S_DATABASE_INSTALLED:
  1469. case ATTR_M_DATABASE_INSTALLED:
  1470. pOperand->dtType = DT_LITERAL_BOOL;
  1471. pOperand->bData = CheckIfInstalledDB(pDatabase->szGUID);
  1472. break;
  1473. case ATTR_S_DATABASE_NAME:
  1474. case ATTR_M_DATABASE_NAME:
  1475. pOperand->SetString(pDatabase->strName);
  1476. break;
  1477. case ATTR_S_DATABASE_PATH:
  1478. case ATTR_M_DATABASE_PATH:
  1479. pOperand->SetString(pDatabase->strPath);
  1480. break;
  1481. case ATTR_S_ENTRY_APPHELPTYPE:
  1482. case ATTR_M_ENTRY_APPHELPTYPE:
  1483. pOperand->dtType = DT_LITERAL_INT;
  1484. pOperand->iData = pEntry->appHelp.severity; // BUGBUG: do we set the severity properly
  1485. break;
  1486. case ATTR_S_ENTRY_APPHELPUSED:
  1487. case ATTR_M_ENTRY_APPHELPUSED:
  1488. pOperand->dtType = DT_LITERAL_BOOL;
  1489. pOperand->bData = pEntry->appHelp.bPresent;
  1490. break;
  1491. case ATTR_S_ENTRY_DISABLED:
  1492. case ATTR_M_ENTRY_DISABLED:
  1493. pOperand->dtType = DT_LITERAL_BOOL;
  1494. pOperand->bData = pEntry->bDisablePerMachine || pEntry->bDisablePerUser;
  1495. break;
  1496. case ATTR_S_ENTRY_EXEPATH:
  1497. case ATTR_M_ENTRY_EXEPATH:
  1498. pOperand->SetString(pEntry->strExeName);
  1499. break;
  1500. case ATTR_S_ENTRY_GUID:
  1501. case ATTR_M_ENTRY_GUID:
  1502. pOperand->SetString(pEntry->szGUID);
  1503. break;
  1504. case ATTR_S_ENTRY_LAYER_COUNT:
  1505. case ATTR_M_ENTRY_LAYER_COUNT:
  1506. pOperand->dtType = DT_LITERAL_INT;
  1507. pOperand->iData = GetLayerCount((LPARAM) pEntry, TYPE_ENTRY);
  1508. break;
  1509. case ATTR_S_ENTRY_MATCH_COUNT:
  1510. case ATTR_M_ENTRY_MATCH_COUNT:
  1511. pOperand->dtType = DT_LITERAL_INT;
  1512. pOperand->iData = GetMatchCount(pEntry);
  1513. break;
  1514. case ATTR_S_ENTRY_PATCH_COUNT:
  1515. case ATTR_M_ENTRY_PATCH_COUNT:
  1516. pOperand->dtType = DT_LITERAL_INT;
  1517. pOperand->iData = GetPatchCount((LPARAM) pEntry, TYPE_ENTRY);
  1518. break;
  1519. case ATTR_S_ENTRY_SHIMFLAG_COUNT:
  1520. case ATTR_M_ENTRY_SHIMFLAG_COUNT:
  1521. pOperand->dtType = DT_LITERAL_INT;
  1522. pOperand->iData = GetShimFlagCount((LPARAM) pEntry, TYPE_ENTRY);
  1523. break;
  1524. case ATTR_S_SHIM_NAME:
  1525. GetFixesAppliedToEntry(pEntry, strTemp);
  1526. pOperand->SetString((PCTSTR)strTemp);
  1527. break;
  1528. case ATTR_S_LAYER_NAME:
  1529. GetLayersAppliedToEntry(pEntry, strTemp);
  1530. pOperand->SetString((PCTSTR)strTemp);
  1531. break;
  1532. case ATTR_S_MATCHFILE_NAME:
  1533. GetMatchingFilesForEntry(pEntry, strTemp);
  1534. pOperand->SetString((PCTSTR)strTemp);
  1535. break;
  1536. case ATTR_S_PATCH_NAME:
  1537. GetPatchesAppliedToEntry(pEntry, strTemp);
  1538. pOperand->SetString((PCTSTR)strTemp);
  1539. break;
  1540. }
  1541. }
  1542. return TRUE;
  1543. }
  1544. BOOL
  1545. Statement::ApplyHasOperator(
  1546. IN PDBENTRY pEntry,
  1547. IN PNODE pOperandLeft,
  1548. IN OUT PTSTR pszName
  1549. )
  1550. /*++
  1551. Statement::ApplyHasOperator
  1552. Params:
  1553. IN PDBENTRY pEntry: The entry which is being checked to see if it
  1554. satisfies the post fix expression.
  1555. IN PNODE pOperandLeft: The left operand of the HAS operator
  1556. IN OUT PCTSTR pszName: The right operand of the HAS operator. We will
  1557. trim this so it will get modified
  1558. Desc: Applies the "HAS" operator.
  1559. Notes: The HAS operator is required because there can be some attributes which are multi-valued
  1560. For these attributes, we might wish to know, if it 'has' a particular string
  1561. The attributes for which the HAS operator can be applied are:
  1562. layer name, shim name and matching file name. Trying to use any other operand as the
  1563. left side operand will give a sql error
  1564. --*/
  1565. {
  1566. BOOL bFound = FALSE;
  1567. if (pEntry == NULL || pOperandLeft == NULL || pszName == NULL) {
  1568. assert(FALSE);
  1569. return FALSE;
  1570. }
  1571. switch (pOperandLeft->attrMatch) {
  1572. case ATTR_M_LAYER_NAME:
  1573. {
  1574. PLAYER_FIX_LIST plfl;
  1575. plfl = pEntry->pFirstLayer;
  1576. while (plfl) {
  1577. assert (plfl->pLayerFix);
  1578. if (CheckIfContains(plfl->pLayerFix->strName, pszName)) {
  1579. bFound = TRUE;
  1580. break;
  1581. }
  1582. plfl = plfl->pNext;
  1583. }
  1584. }
  1585. break;
  1586. case ATTR_M_MATCHFILE_NAME:
  1587. {
  1588. PMATCHINGFILE pMatch;
  1589. pMatch = pEntry->pFirstMatchingFile;
  1590. while (pMatch) {
  1591. if (CheckIfContains(pMatch->strMatchName, pszName)) {
  1592. bFound = TRUE;
  1593. break;
  1594. }
  1595. pMatch = pMatch->pNext;
  1596. }
  1597. }
  1598. break;
  1599. case ATTR_M_PATCH_NAME:
  1600. {
  1601. PPATCH_FIX_LIST ppfl;
  1602. ppfl = pEntry->pFirstPatch;
  1603. while (ppfl) {
  1604. assert(ppfl->pPatchFix);
  1605. if (CheckIfContains(ppfl->pPatchFix->strName, pszName)) {
  1606. bFound = TRUE;
  1607. break;
  1608. }
  1609. ppfl = ppfl->pNext;
  1610. }
  1611. }
  1612. break;
  1613. case ATTR_M_SHIM_NAME:
  1614. {
  1615. //
  1616. // For both shims and flags
  1617. //
  1618. PSHIM_FIX_LIST psfl;
  1619. psfl = pEntry->pFirstShim;
  1620. while (psfl) {
  1621. assert(psfl->pShimFix);
  1622. if (CheckIfContains(psfl->pShimFix->strName, pszName)) {
  1623. bFound = TRUE;
  1624. break;
  1625. }
  1626. psfl = psfl->pNext;
  1627. }
  1628. if (bFound == FALSE) {
  1629. //
  1630. // Now look in flags
  1631. //
  1632. PFLAG_FIX_LIST pffl;
  1633. pffl = pEntry->pFirstFlag;
  1634. while (pffl) {
  1635. assert(pffl->pFlagFix);
  1636. if (CheckIfContains(pffl->pFlagFix->strName, pszName)) {
  1637. bFound = TRUE;
  1638. break;
  1639. }
  1640. pffl = pffl->pNext;
  1641. }
  1642. }
  1643. }
  1644. break;
  1645. }
  1646. return bFound;
  1647. }
  1648. PNODE
  1649. Statement::CheckAndAddConstants(
  1650. IN PCTSTR pszCurrent
  1651. )
  1652. /*++
  1653. Statement::CheckAndAddConstants
  1654. Desc: Checks if the string passed is one of the constants and if yes, then it
  1655. makes a node and adds it to the passed infix nodelist.
  1656. Params:
  1657. IN PCTSTR pszCurrent: The string that we want to check for a constant
  1658. Return:
  1659. TRUE: The passed string was a constant and it was added to the infix nodelist
  1660. FALSE: Otherwise.
  1661. --*/
  1662. {
  1663. BOOL bFound = FALSE;
  1664. PNODE pNode = NULL;
  1665. for (UINT uIndex = 0; uIndex < ARRAYSIZE(Constants); ++uIndex) {
  1666. if (lstrcmpi(Constants[uIndex].szName, pszCurrent) == 0) {
  1667. pNode = new NODE(Constants[uIndex].dtType, Constants[uIndex].iValue);
  1668. if (pNode == NULL) {
  1669. MEM_ERR;
  1670. }
  1671. break;
  1672. }
  1673. }
  1674. return pNode;
  1675. }
  1676. PNODELIST
  1677. Statement::GetShowList(
  1678. void
  1679. )
  1680. /*++
  1681. Statement::GetShowList
  1682. Desc: Returns the attribute show list associated with a statement object
  1683. --*/
  1684. {
  1685. return &AttributeShowList;
  1686. }
  1687. void
  1688. Statement::Close(
  1689. void
  1690. )
  1691. /*++
  1692. Statement::Close
  1693. Desc: Closes the statement, removes elements from the AttributeList and closes
  1694. the result set
  1695. --*/
  1696. {
  1697. PNODE pNodeTemp = NULL;
  1698. //
  1699. // Free the show list
  1700. //
  1701. while (AttributeShowList.m_pHead) {
  1702. pNodeTemp = AttributeShowList.m_pHead->pNext;
  1703. delete AttributeShowList.m_pHead;
  1704. AttributeShowList.m_pHead = pNodeTemp;
  1705. }
  1706. AttributeShowList.m_pTail = NULL;
  1707. AttributeShowList.m_uCount = 0;
  1708. //
  1709. // Free the resultSelt
  1710. //
  1711. resultset.Close();
  1712. }
  1713. INT
  1714. Statement::GetErrorCode(
  1715. void
  1716. )
  1717. /*++
  1718. Statement::GetErrorCode
  1719. Desc: Returns the sql error code
  1720. --*/
  1721. {
  1722. return uErrorCode;
  1723. }
  1724. void
  1725. Statement::GetErrorMsg(
  1726. OUT CSTRING &strErrorMsg
  1727. )
  1728. /*++
  1729. Statement::GetErrorMsg
  1730. Desc: Gets the error message associated with the present error
  1731. Params:
  1732. OUT CSTRING &strErrorMsg
  1733. Return:
  1734. void
  1735. --*/
  1736. {
  1737. UINT uError = uErrorCode;
  1738. switch (uError) {
  1739. case ERROR_FROM_NOTFOUND:
  1740. strErrorMsg = GetString(IDS_ERROR_FROM_NOTFOUND);
  1741. break;
  1742. case ERROR_IMPROPERWHERE_FOUND:
  1743. strErrorMsg = GetString(IDS_ERROR_IMPROPERWHERE_FOUND);
  1744. break;
  1745. case ERROR_INVALID_AND_OPERANDS:
  1746. strErrorMsg = GetString(IDS_ERROR_INVALID_AND_OPERANDS);
  1747. break;
  1748. case ERROR_INVALID_CONTAINS_OPERANDS:
  1749. strErrorMsg = GetString(IDS_ERROR_INVALID_CONTAINS_OPERANDS);
  1750. break;
  1751. case ERROR_INVALID_DBTYPE_INFROM:
  1752. strErrorMsg = GetString(IDS_ERROR_INVALID_DBTYPE_INFROM);
  1753. break;
  1754. case ERROR_INVALID_GE_OPERANDS:
  1755. strErrorMsg = GetString(IDS_ERROR_INVALID_GE_OPERANDS);
  1756. break;
  1757. case ERROR_INVALID_GT_OPERANDS:
  1758. strErrorMsg = GetString(IDS_ERROR_INVALID_GT_OPERANDS);
  1759. break;
  1760. case ERROR_INVALID_HAS_OPERANDS:
  1761. strErrorMsg = GetString(IDS_ERROR_INVALID_HAS_OPERANDS);
  1762. break;
  1763. case ERROR_INVALID_LE_OPERANDS:
  1764. strErrorMsg = GetString(IDS_ERROR_INVALID_LE_OPERANDS);
  1765. break;
  1766. case ERROR_INVALID_LT_OPERANDS:
  1767. strErrorMsg = GetString(IDS_ERROR_INVALID_LT_OPERANDS);
  1768. break;
  1769. case ERROR_INVALID_OR_OPERANDS:
  1770. strErrorMsg = GetString(IDS_ERROR_INVALID_OR_OPERANDS);
  1771. break;
  1772. case ERROR_INVALID_SELECTPARAM:
  1773. strErrorMsg = GetString(IDS_ERROR_INVALID_SELECTPARAM);
  1774. break;
  1775. case ERROR_OPERANDS_DONOTMATCH:
  1776. strErrorMsg = GetString(IDS_ERROR_OPERANDS_DONOTMATCH);
  1777. break;
  1778. case ERROR_SELECT_NOTFOUND:
  1779. strErrorMsg = GetString(IDS_ERROR_SELECT_NOTFOUND);
  1780. break;
  1781. case ERROR_STRING_NOT_TERMINATED:
  1782. strErrorMsg = GetString(IDS_ERROR_STRING_NOT_TERMINATED);
  1783. break;
  1784. case ERROR_PARENTHESIS_COUNT:
  1785. strErrorMsg = GetString(IDS_ERROR_PARENTHESIS_COUNT);
  1786. break;
  1787. case ERROR_WRONGNUMBER_OPERANDS:
  1788. strErrorMsg = GetString(IDS_ERROR_WRONGNUMBER_OPERANDS);
  1789. break;
  1790. }
  1791. }
  1792. ///////////////////////////////////////////////////////////////////////////////
  1793. //
  1794. //
  1795. // The ResultSet Class member functions
  1796. //
  1797. //
  1798. ///////////////////////////////////////////////////////////////////////////////
  1799. void
  1800. ResultSet::AddAtLast(
  1801. IN PRESULT_ITEM pNew
  1802. )
  1803. /*++
  1804. ResultSet::AddAtLast
  1805. Desc: Adds a new PRESULT_ITEM to the end of the result-set
  1806. Params:
  1807. IN PRESULT_ITEM pNew: The PRESULT_ITEM to add
  1808. Return:
  1809. void
  1810. --*/
  1811. {
  1812. if (pNew == NULL) {
  1813. assert(FALSE);
  1814. return;
  1815. }
  1816. pNew->pNext = NULL;
  1817. if (m_pResultLast) {
  1818. pNew->pPrev = m_pResultLast;
  1819. m_pResultLast->pNext = pNew;
  1820. m_pResultLast = pNew;
  1821. } else {
  1822. m_pResultHead = m_pResultLast = pNew;
  1823. }
  1824. m_uCount++;
  1825. }
  1826. void
  1827. ResultSet::AddAtBeg(
  1828. PRESULT_ITEM pNew
  1829. )
  1830. /*++
  1831. ResultSet::AddAtBeg
  1832. Desc: Adds a new PRESULT_ITEM to the beginning of the result-set
  1833. Params:
  1834. IN PRESULT_ITEM pNew: The PRESULT_ITEM to add
  1835. Return:
  1836. void
  1837. --*/
  1838. {
  1839. if (m_pResultHead) {
  1840. m_pResultHead->pPrev = pNew;
  1841. }
  1842. pNew->pNext = m_pResultHead;
  1843. m_pResultHead = pNew;
  1844. if (m_pResultLast == NULL) {
  1845. m_pResultLast = pNew;
  1846. }
  1847. m_uCount++;
  1848. }
  1849. INT
  1850. ResultSet::GetRow(
  1851. IN PRESULT_ITEM pResultItem,
  1852. OUT PNODE pArNodes
  1853. )
  1854. /*++
  1855. ResultSet::GetRow
  1856. Desc: For the pResultItem, gets the row of the values.
  1857. Caller must free that after use.
  1858. Params:
  1859. IN PRESULT_ITEM pResultItem: The PRESULT_ITEM for which we want the row
  1860. OUT PNODE pArNodes: The pointer to an array of Statement::AttributeShowList::m_uCount
  1861. nodes. (This is the number of attributes that are in the SELECT clause)
  1862. Return: Number of items in the row. This should be equal to the number of attributes that
  1863. are in the SELECT clause
  1864. --*/
  1865. {
  1866. PNODE pNodeTemp = NULL;
  1867. UINT uIndex = 0;
  1868. if (m_pShowList == NULL || m_pShowList->m_uCount == 0) {
  1869. assert(FALSE);
  1870. return 0;
  1871. }
  1872. for (uIndex = 0, pNodeTemp = m_pShowList->m_pHead;
  1873. pNodeTemp;
  1874. pNodeTemp = pNodeTemp->pNext, ++uIndex) {
  1875. pArNodes[uIndex].dtType = DT_ATTRSHOW;
  1876. pArNodes[uIndex].attrShow = pNodeTemp->attrShow;
  1877. SetValuesForOperands(pResultItem->pDatabase,
  1878. pResultItem->pEntry,
  1879. &pArNodes[uIndex]);
  1880. }
  1881. assert(uIndex == m_pShowList->m_uCount);
  1882. return m_pShowList->m_uCount;
  1883. }
  1884. void
  1885. ResultSet::SetShowList(
  1886. IN PNODELIST pShowList
  1887. )
  1888. /*++
  1889. ResultSet::SetShowList
  1890. Desc: Sets the show attributes list pointer for the result set. This in fact
  1891. points to the show attributes list of the statement
  1892. Params:
  1893. IN PNODELIST pShowList: Pointer to the show attributes list
  1894. Return:
  1895. void
  1896. --*/
  1897. {
  1898. m_pShowList = pShowList;
  1899. }
  1900. PRESULT_ITEM
  1901. ResultSet::GetCursor(
  1902. void
  1903. )
  1904. /*++
  1905. ResultSet::GetCursor
  1906. Desc: The present cursor. The result set comprises of PRESULT_ITEM, this function
  1907. returns the present PRESULT_ITEM
  1908. --*/
  1909. {
  1910. return m_pCursor;
  1911. }
  1912. INT
  1913. ResultSet::GetCurrentRow(
  1914. OUT PNODE pArNodes
  1915. )
  1916. /*++
  1917. ResultSet::GetCurrentRow
  1918. Desc: Gets the row (values for the attributes in the show list),
  1919. for the present cursor. The result set comprises of PRESULT_ITEM,
  1920. this function returns the values of the attributes in the SELECT clause
  1921. (the show list) for the present PRESULT_ITEM
  1922. Params:
  1923. OUT PNODE pArNodes: The pointer to an array of
  1924. Statement::AttributeShowList::m_uCount nodes.
  1925. (This is the number of attributes that are in the SELECT clause)
  1926. Return: Number of items in the row. This should be equal to the number of attributes that
  1927. are in the SELECT clause
  1928. --*/
  1929. {
  1930. return GetRow(m_pCursor, pArNodes);
  1931. }
  1932. PRESULT_ITEM
  1933. ResultSet::GetNext(
  1934. void
  1935. )
  1936. /*++
  1937. ResultSet::GetNext
  1938. Desc: The next cursor if cursor is not NULL, otherwise sets cursor to the first
  1939. item in the result set and returns it
  1940. Notes: Initially the cursor is NULL, meaning parked before the first result
  1941. item. Result items are of type PRESULT_ITEM
  1942. --*/
  1943. {
  1944. if (m_pCursor) {
  1945. m_pCursor = m_pCursor->pNext;
  1946. return m_pCursor;
  1947. } else {
  1948. return m_pCursor = m_pResultHead;
  1949. }
  1950. }
  1951. void
  1952. ResultSet::Close(
  1953. void
  1954. )
  1955. /*++
  1956. ResultSet::Close
  1957. Desc: Deletes all the items in the result set
  1958. --*/
  1959. {
  1960. PRESULT_ITEM pResult;
  1961. while (m_pResultHead) {
  1962. pResult = m_pResultHead->pNext;
  1963. delete m_pResultHead;
  1964. m_pResultHead = pResult;
  1965. }
  1966. m_pCursor = m_pResultHead = m_pResultLast = NULL;
  1967. m_uCount = 0;
  1968. }
  1969. INT
  1970. ResultSet::GetCount(
  1971. void
  1972. )
  1973. /*++
  1974. ResultSet::GetCount
  1975. Desc: Returns the number of results in the result set
  1976. Return: The number of results in the result set
  1977. --*/
  1978. {
  1979. return m_uCount;
  1980. }
  1981. ///////////////////////////////////////////////////////////////////////////////
  1982. //
  1983. //
  1984. // NODE functions
  1985. //
  1986. //
  1987. ///////////////////////////////////////////////////////////////////////////////
  1988. TCHAR*
  1989. NODE::ToString(
  1990. OUT TCHAR* pszBuffer,
  1991. IN UINT chLength
  1992. )
  1993. /*++
  1994. NODE::ToString
  1995. Desc: Converts the data for a node into a string type, so that we can display
  1996. that in a list view
  1997. Params:
  1998. OUT TCHAR* pszBuffer: The buffer in which we wanwt to put the string
  1999. IN UINT chLength: Length of the buffer in characters
  2000. Return: Pointer to pszBuffer
  2001. --*/
  2002. {
  2003. switch (dtType) {
  2004. case DT_LITERAL_SZ:
  2005. SafeCpyN(pszBuffer, szString, chLength);
  2006. break;
  2007. case DT_LITERAL_BOOL:
  2008. if (bData) {
  2009. SafeCpyN(pszBuffer, GetString(IDS_YES), chLength);
  2010. } else {
  2011. SafeCpyN(pszBuffer, GetString(IDS_NO), chLength);
  2012. }
  2013. break;
  2014. case DT_LITERAL_INT:
  2015. assert(chLength > 32);
  2016. _itot(iData, pszBuffer, 10);
  2017. break;
  2018. case DT_ATTRSHOW:
  2019. for (UINT uIndex = 0; uIndex < ARRAYSIZE(AttributeShowMapping); ++uIndex) {
  2020. if (AttributeShowMapping[uIndex].attr == attrShow) {
  2021. GetString(AttributeShowMapping[uIndex].iResourceId, pszBuffer, chLength);
  2022. break;
  2023. }
  2024. }
  2025. break;
  2026. case DT_ATTRMATCH:
  2027. for (UINT uIndex = 0; uIndex < ARRAYSIZE(AttributeMatchMapping); ++uIndex) {
  2028. if (AttributeMatchMapping[uIndex].attr == attrShow) {
  2029. SafeCpyN(pszBuffer,
  2030. AttributeMatchMapping[uIndex].szAttribute,
  2031. chLength);
  2032. break;
  2033. }
  2034. }
  2035. break;
  2036. }
  2037. return pszBuffer;
  2038. }
  2039. INT
  2040. GetSelectAttrCount(
  2041. void
  2042. )
  2043. /*++
  2044. GetSelectAttrCount
  2045. Desc: Gets the count of total available attributes that can be put in the SELECT clause of SQL
  2046. Return: The count of total available attributes that can be put in the SELECT clause of SQL
  2047. --*/
  2048. {
  2049. return ARRAYSIZE(AttributeShowMapping);
  2050. }
  2051. INT
  2052. GetMatchAttrCount(
  2053. void
  2054. )
  2055. /*++
  2056. GetMatchAttrCount
  2057. Desc: Gets the count of total available attributes that can be put in the WHERE clause of SQL
  2058. Return: The count of total available attributes that can be put in the WHERE clause of SQL
  2059. --*/
  2060. {
  2061. return ARRAYSIZE(AttributeMatchMapping);
  2062. }
  2063. BOOL
  2064. CheckIfContains(
  2065. IN PCTSTR pszString,
  2066. IN OUT PTSTR pszMatch
  2067. )
  2068. /*++
  2069. CheckIfContains
  2070. Desc: Checks if string pszMatch is contained in string pszString.
  2071. Use wild cards for specifying sub-string matching
  2072. The wild card character is %. So if we do CheckIfContains(L"Hello world", "Hello") this
  2073. will be false, but if we do CheckIfContains(L"Hello world", "Hello%") this
  2074. will be true
  2075. Params:
  2076. IN PCTSTR pszString: The string to search into
  2077. IN OUT PCTSTR pszMatch: The string to search for in the above string
  2078. Return:
  2079. TRUE: pszMatch exists in pszString
  2080. FALSE: Otherwise
  2081. Note: Comparison is NOT case sensitive
  2082. --*/
  2083. {
  2084. if (pszString == NULL) {
  2085. return FALSE;
  2086. }
  2087. if (pszMatch == NULL) {
  2088. assert(FALSE);
  2089. return FALSE;
  2090. }
  2091. if (*pszMatch == NULL) {
  2092. return TRUE;
  2093. }
  2094. BOOL fCheckSuffix = FALSE, fCheckPrefix = FALSE, fResult = FALSE;
  2095. TCHAR* pchLastPosition = NULL;
  2096. TCHAR* pszTempMatch = NULL;
  2097. K_SIZE k_size = lstrlen(pszMatch) + 1;
  2098. pszTempMatch = new TCHAR[k_size];
  2099. if (pszTempMatch == NULL) {
  2100. MEM_ERR;
  2101. return FALSE;
  2102. }
  2103. SafeCpyN(pszTempMatch, pszMatch, k_size);
  2104. CSTRING::Trim(pszTempMatch);
  2105. fCheckSuffix = (pszTempMatch[0] == TEXT('%'));
  2106. //
  2107. // Only % ?
  2108. //
  2109. if (fCheckSuffix && pszTempMatch[1] == 0) {
  2110. fResult = TRUE;
  2111. goto End;
  2112. }
  2113. pchLastPosition = _tcschr(pszTempMatch + 1, TEXT('%'));
  2114. if (pchLastPosition) {
  2115. fCheckPrefix = TRUE;
  2116. *pchLastPosition = 0; // Remove the last %
  2117. }
  2118. if (fCheckPrefix && !fCheckSuffix) {
  2119. fResult = CSTRING::StrStrI(pszString, pszTempMatch) == pszString ? TRUE : FALSE;
  2120. } else if (fCheckSuffix && !fCheckPrefix) {
  2121. fResult = CSTRING::EndsWith(pszString, pszTempMatch + 1);
  2122. } else if (fCheckPrefix && fCheckSuffix) {
  2123. fResult = CSTRING::StrStrI(pszString, pszTempMatch + 1) != NULL ? TRUE : FALSE;
  2124. } else {
  2125. fResult = lstrcmpi(pszString, pszTempMatch) == 0 ? TRUE : FALSE;
  2126. }
  2127. if (fCheckPrefix) {
  2128. //
  2129. // Revert back the last character, the match string might be used for further searches
  2130. //
  2131. *pchLastPosition = TEXT('%');
  2132. }
  2133. End:
  2134. if (pszTempMatch) {
  2135. delete[] pszTempMatch;
  2136. pszTempMatch = NULL;
  2137. }
  2138. return fResult;
  2139. }