Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1103 lines
41 KiB

  1. /***************************************************************************/
  2. /* OPTIMIZE.C */
  3. /* Copyright (C) 1995-96 SYWARE Inc., All rights reserved */
  4. /***************************************************************************/
  5. // Commenting #define out - causing compiler error - not sure if needed, compiles
  6. // okay without it.
  7. //#define WINVER 0x0400
  8. #include "precomp.h"
  9. #include "wbemidl.h"
  10. #include <comdef.h>
  11. //smart pointer
  12. _COM_SMARTPTR_TYPEDEF(IWbemServices, IID_IWbemServices);
  13. _COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, IID_IEnumWbemClassObject);
  14. //_COM_SMARTPTR_TYPEDEF(IWbemContext, IID_IWbemContext );
  15. _COM_SMARTPTR_TYPEDEF(IWbemLocator, IID_IWbemLocator);
  16. #include "drdbdr.h"
  17. /***************************************************************************/
  18. /***************************************************************************/
  19. /***************************************************************************/
  20. /***************************************************************************/
  21. /***************************************************************************/
  22. /* MSAccess commonly passes predicates in the form: */
  23. /* */
  24. /* OR */
  25. /* / \ */
  26. /* key-cond OR */
  27. /* / \ */
  28. /* key-cond OR */
  29. /* / \ */
  30. /* key-cond OR */
  31. /* / \ */
  32. /* key-cond OR */
  33. /* / \ */
  34. /* key-cond OR */
  35. /* / \ */
  36. /* key-cond OR */
  37. /* / \ */
  38. /* key-cond OR */
  39. /* / \ */
  40. /* key-cond OR */
  41. /* / \ */
  42. /* key-cond key-cond */
  43. /* */
  44. /* Note: there are exactly 9 OR nodes. */
  45. /* */
  46. /* There are ten key-cond in the tree and the structure of all ten are the */
  47. /* same. Each key-cond node is either a basic-model of: */
  48. /* */
  49. /* EQUAL */
  50. /* / \ */
  51. /* COLUMN PARAMETER */
  52. /* */
  53. /* or the complex-model: */
  54. /* AND */
  55. /* / \ */
  56. /* basic-model AND */
  57. /* / \ */
  58. /* basic-model . */
  59. /* . */
  60. /* . */
  61. /* AND */
  62. /* / \ */
  63. /* basic-model basic-model */
  64. /* */
  65. /* Note: there are a small number of AND nodex (6 or less) */
  66. /* */
  67. /* */
  68. /* The following routines test a predicate to see if it is in this form: */
  69. /***************************************************************************/
  70. BOOL INTFUNC CheckBasicModel(LPSQLTREE lpSql, SQLNODEIDX predicate)
  71. /* Tests to see if given node is in basic-model form */
  72. {
  73. LPSQLNODE lpSqlNode;
  74. LPSQLNODE lpSqlNodeLeft;
  75. LPSQLNODE lpSqlNodeRight;
  76. if (predicate == NO_SQLNODE)
  77. return FALSE;
  78. lpSqlNode = ToNode(lpSql, predicate);
  79. if (lpSqlNode->sqlNodeType != NODE_TYPE_COMPARISON)
  80. return FALSE;
  81. if (lpSqlNode->node.comparison.Operator != OP_EQ)
  82. return FALSE;
  83. lpSqlNodeLeft = ToNode(lpSql, lpSqlNode->node.comparison.Left);
  84. if (lpSqlNodeLeft->sqlNodeType != NODE_TYPE_COLUMN)
  85. return FALSE;
  86. lpSqlNodeRight = ToNode(lpSql, lpSqlNode->node.comparison.Right);
  87. if (lpSqlNodeRight->sqlNodeType != NODE_TYPE_PARAMETER)
  88. return FALSE;
  89. return TRUE;
  90. }
  91. /***************************************************************************/
  92. BOOL INTFUNC CheckModel(LPSQLTREE lpSql, SQLNODEIDX predicate, int count)
  93. /* Tests to see if given node is in basic-model or complex-model form */
  94. {
  95. LPSQLNODE lpSqlNode;
  96. if (count > 6)
  97. return FALSE;
  98. lpSqlNode = ToNode(lpSql, predicate);
  99. if (lpSqlNode->sqlNodeType == NODE_TYPE_COMPARISON)
  100. return CheckBasicModel(lpSql, predicate);
  101. if (lpSqlNode->sqlNodeType != NODE_TYPE_BOOLEAN)
  102. return FALSE;
  103. if (lpSqlNode->node.boolean.Operator != OP_AND)
  104. return FALSE;
  105. if (!CheckBasicModel(lpSql, lpSqlNode->node.boolean.Left))
  106. return FALSE;
  107. return CheckModel(lpSql, lpSqlNode->node.boolean.Right, count + 1);
  108. }
  109. /***************************************************************************/
  110. SQLNODEIDX INTFUNC FindModel(LPSQLTREE lpSql, SQLNODEIDX predicate, int count)
  111. /* Tests to make sure predicate has nine OR nodes and returns the right */
  112. /* child of the ninth one */
  113. {
  114. LPSQLNODE lpSqlNode;
  115. if (predicate == NO_SQLNODE)
  116. return NO_SQLNODE;
  117. lpSqlNode = ToNode(lpSql, predicate);
  118. if (lpSqlNode->sqlNodeType != NODE_TYPE_BOOLEAN)
  119. return NO_SQLNODE;
  120. if (lpSqlNode->node.boolean.Operator != OP_OR)
  121. return NO_SQLNODE;
  122. if (count < 9)
  123. return FindModel(lpSql, lpSqlNode->node.boolean.Right, count + 1);
  124. if (!CheckModel(lpSql, lpSqlNode->node.boolean.Right, 1))
  125. return NO_SQLNODE;
  126. return lpSqlNode->node.boolean.Right;
  127. }
  128. /***************************************************************************/
  129. BOOL INTFUNC CompareTree(LPSQLTREE lpSql, SQLNODEIDX tree, SQLNODEIDX model)
  130. /* Tests to see if the given tree and model have the same structure */
  131. {
  132. LPSQLNODE lpSqlNode;
  133. LPSQLNODE lpSqlNodeModel;
  134. if (tree == NO_SQLNODE)
  135. return FALSE;
  136. lpSqlNode = ToNode(lpSql, tree);
  137. lpSqlNodeModel = ToNode(lpSql, model);
  138. if (lpSqlNode->sqlNodeType != lpSqlNodeModel->sqlNodeType)
  139. return FALSE;
  140. switch (lpSqlNodeModel->sqlNodeType) {
  141. case NODE_TYPE_BOOLEAN:
  142. if (lpSqlNode->node.boolean.Operator !=
  143. lpSqlNodeModel->node.boolean.Operator)
  144. return FALSE;
  145. if (!CompareTree(lpSql, lpSqlNode->node.boolean.Left,
  146. lpSqlNodeModel->node.boolean.Left))
  147. return FALSE;
  148. if (!CompareTree(lpSql, lpSqlNode->node.boolean.Right,
  149. lpSqlNodeModel->node.boolean.Right))
  150. return FALSE;
  151. break;
  152. case NODE_TYPE_COMPARISON:
  153. if (lpSqlNode->node.comparison.Operator !=
  154. lpSqlNodeModel->node.comparison.Operator)
  155. return FALSE;
  156. if (!CompareTree(lpSql, lpSqlNode->node.comparison.Left,
  157. lpSqlNodeModel->node.comparison.Left))
  158. return FALSE;
  159. if (!CompareTree(lpSql, lpSqlNode->node.comparison.Right,
  160. lpSqlNodeModel->node.comparison.Right))
  161. return FALSE;
  162. break;
  163. case NODE_TYPE_COLUMN:
  164. if (lpSqlNode->node.column.Id != lpSqlNodeModel->node.column.Id)
  165. return FALSE;
  166. break;
  167. case NODE_TYPE_PARAMETER:
  168. break;
  169. default:
  170. return FALSE;
  171. }
  172. return TRUE;
  173. }
  174. /***************************************************************************/
  175. BOOL INTFUNC CheckMSAccessPredicate(LPSQLTREE lpSql, SQLNODEIDX predicate)
  176. /* Checks to see if prediciate is in the form documented above */
  177. {
  178. SQLNODEIDX model;
  179. LPSQLNODE lpSqlNode;
  180. WORD i;
  181. model = FindModel(lpSql, predicate, 1);
  182. if (model == NO_SQLNODE)
  183. return FALSE;
  184. lpSqlNode = ToNode(lpSql, predicate);
  185. for (i = 1; i < 10; i++) {
  186. if (!CompareTree(lpSql, lpSqlNode->node.boolean.Left, model))
  187. return FALSE;
  188. lpSqlNode = ToNode(lpSql, lpSqlNode->node.boolean.Right);
  189. }
  190. return TRUE;
  191. }
  192. /***************************************************************************/
  193. /***************************************************************************/
  194. RETCODE INTFUNC FindRestriction(LPSQLTREE lpSql, BOOL fCaseSensitive,
  195. LPSQLNODE lpSqlNodeTable, SQLNODEIDX idxPredicate,
  196. SQLNODEIDX idxEnclosingStatement,
  197. UWORD FAR *lpcRestriction, SQLNODEIDX FAR *lpRestriction)
  198. /* Find the index of NODE_TYPE_COMPARISON nodes in the form: */
  199. /* */
  200. /* <column> <op> <value> */
  201. /* <column> <op> <anothercolumn> */
  202. /* */
  203. /* where <column> is a column of the table identified by lpSqlNodeTable and */
  204. /* <anothercolumn> is a column in a slower moving table. The nodes are */
  205. /* returned in fSelectivity order (the most selective being first). */
  206. {
  207. LPSQLNODE lpSqlNodePredicate;
  208. LPSQLNODE lpSqlNodeRight;
  209. SQLNODEIDX idxLeft;
  210. SQLNODEIDX idxRight;
  211. LPSQLNODE lpSqlNodeColumn;
  212. LPSQLNODE lpSqlNodeValue;
  213. BOOL fSwap;
  214. LPUSTR lpTableAlias;
  215. LPUSTR lpColumnAlias;
  216. LPSQLNODE lpSqlNodeTables;
  217. LPSQLNODE lpSqlNodeOtherTable;
  218. SQLNODEIDX idxPrev;
  219. SQLNODEIDX idxCurr;
  220. LPSQLNODE lpSqlNodePredicatePrev;
  221. LPSQLNODE lpSqlNodePredicateCurr;
  222. BOOL fRightMightBeSlower;
  223. /* If no predicate, return */
  224. if (idxPredicate == NO_SQLNODE)
  225. return ERR_SUCCESS;
  226. /* What kind of predicate? */
  227. lpSqlNodePredicate = ToNode(lpSql, idxPredicate);
  228. switch (lpSqlNodePredicate->sqlNodeType) {
  229. case NODE_TYPE_CREATE:
  230. case NODE_TYPE_DROP:
  231. case NODE_TYPE_SELECT:
  232. case NODE_TYPE_INSERT:
  233. case NODE_TYPE_DELETE:
  234. case NODE_TYPE_UPDATE:
  235. case NODE_TYPE_CREATEINDEX:
  236. case NODE_TYPE_DROPINDEX:
  237. case NODE_TYPE_PASSTHROUGH:
  238. case NODE_TYPE_TABLES:
  239. case NODE_TYPE_VALUES:
  240. case NODE_TYPE_COLUMNS:
  241. case NODE_TYPE_SORTCOLUMNS:
  242. case NODE_TYPE_GROUPBYCOLUMNS:
  243. case NODE_TYPE_UPDATEVALUES:
  244. case NODE_TYPE_CREATECOLS:
  245. return ERR_INTERNAL;
  246. case NODE_TYPE_BOOLEAN:
  247. /* Boolean expression. Look at each sub-expression */
  248. while (TRUE) {
  249. /* If not an AND expression, it can't be used. Stop looking */
  250. if (lpSqlNodePredicate->node.boolean.Operator != OP_AND)
  251. return ERR_SUCCESS;
  252. /* Find nodes on the left side */
  253. FindRestriction(lpSql, fCaseSensitive,
  254. lpSqlNodeTable, lpSqlNodePredicate->node.boolean.Left,
  255. idxEnclosingStatement, lpcRestriction, lpRestriction);
  256. /* Get the right child */
  257. lpSqlNodeRight = ToNode(lpSql, lpSqlNodePredicate->node.boolean.Right);
  258. /* Is it a BOOLEAN node? */
  259. if (lpSqlNodeRight->sqlNodeType != NODE_TYPE_BOOLEAN) {
  260. /* No. Find nodes on the right side */
  261. idxRight = FindRestriction(lpSql, fCaseSensitive,
  262. lpSqlNodeTable, lpSqlNodePredicate->node.boolean.Right,
  263. idxEnclosingStatement, lpcRestriction, lpRestriction);
  264. return ERR_SUCCESS;
  265. }
  266. /* Point to right and continue to walk down the AND nodes */
  267. lpSqlNodePredicate = lpSqlNodeRight;
  268. }
  269. break; /* Control should never get here */
  270. case NODE_TYPE_COMPARISON:
  271. {
  272. /* If not the right operator, the comparison cannot be used */
  273. switch (lpSqlNodePredicate->node.comparison.Operator) {
  274. case OP_EQ:
  275. case OP_NE:
  276. case OP_LE:
  277. case OP_LT:
  278. case OP_GE:
  279. case OP_GT:
  280. break;
  281. case OP_IN:
  282. case OP_NOTIN:
  283. case OP_LIKE:
  284. case OP_NOTLIKE:
  285. case OP_EXISTS:
  286. return ERR_SUCCESS;
  287. default:
  288. return ERR_INTERNAL;
  289. }
  290. /* Get column of the comparison */
  291. lpSqlNodeColumn = ToNode(lpSql, lpSqlNodePredicate->node.comparison.Left);
  292. if (lpSqlNodeColumn->sqlNodeType != NODE_TYPE_COLUMN) {
  293. /* The left side is not a column reference. Swap the two sides */
  294. fSwap = TRUE;
  295. lpSqlNodeValue = lpSqlNodeColumn;
  296. /* Is the right side a column reference? */
  297. lpSqlNodeColumn = ToNode(lpSql, lpSqlNodePredicate->node.comparison.Right);
  298. if (lpSqlNodeColumn->sqlNodeType != NODE_TYPE_COLUMN) {
  299. /* No. The comparison cannot be used. */
  300. return ERR_SUCCESS;
  301. }
  302. }
  303. else {
  304. /* Get the value node */
  305. fSwap = FALSE;
  306. lpSqlNodeValue = ToNode(lpSql, lpSqlNodePredicate->node.comparison.Right);
  307. /* Is the rightside a column too? */
  308. if (lpSqlNodeValue->sqlNodeType == NODE_TYPE_COLUMN) {
  309. /* Yes. Get the list of tables */
  310. lpSqlNodeTables = ToNode(lpSql, idxEnclosingStatement);
  311. /* If not a SELECT statement, <column> <op> <anothercolumn> */
  312. /* cannot be used since the <othercolumn> would have to */
  313. /* to be in the same table. */
  314. if (lpSqlNodeTables->sqlNodeType != NODE_TYPE_SELECT)
  315. return ERR_SUCCESS;
  316. lpSqlNodeTables = ToNode(lpSql, lpSqlNodeTables->node.select.Tables);
  317. /* If the rightside column is in this table, swap the sides */
  318. if (lpSqlNodeTable == ToNode(lpSql, lpSqlNodeValue->node.column.TableIndex))
  319. {
  320. fSwap = TRUE;
  321. lpSqlNodeValue = lpSqlNodeColumn;
  322. lpSqlNodeColumn = ToNode(lpSql,
  323. lpSqlNodePredicate->node.comparison.Right);
  324. }
  325. /* If the rightside column's table is in the same or a */
  326. /* faster moving table than the leftside column's table */
  327. /* the comparison cannot be used since the value of the */
  328. /* rightside column won't be constant for any given row */
  329. /* in the leftside table. See if the rightside column is */
  330. /* in a slower moving table thanthe leftside column. */
  331. fRightMightBeSlower = TRUE;
  332. while (TRUE) {
  333. /* Get next table */
  334. lpSqlNodeOtherTable = ToNode(lpSql, lpSqlNodeTables->node.tables.Table);
  335. lpTableAlias = ToString(lpSql, lpSqlNodeOtherTable->node.table.Alias);
  336. /* If we get here and the current table is the */
  337. /* leftside column's table, that means the rightside */
  338. /* column's table has not been found on the list yet. */
  339. /* Clear the flag so, if we happen to find the */
  340. /* rightside column's table later on in the list, we */
  341. /* will know that the rightside column's table is */
  342. /* definitely not a slower moving than the leftside */
  343. /* column's table */
  344. if (lpSqlNodeOtherTable == ToNode(lpSql,lpSqlNodeColumn->node.column.TableIndex))
  345. return NO_SQLNODE;
  346. /* Case sensitive names? */
  347. if (lpSqlNodeOtherTable == ToNode(lpSql, lpSqlNodeValue->node.column.TableIndex))
  348. break;
  349. /* Are we at the end of the list of tables? */
  350. if (lpSqlNodeTables->node.tables.Next == NO_SQLNODE) {
  351. /* Yes. We never found the rightside column's */
  352. /* table on the list. This means the rightside */
  353. /* column's table must be in a statement that */
  354. /* encloses the SELECT statement identified by */
  355. /* idxEnclosingStatement, so the rightside */
  356. /* column's table is definitately slower moving. */
  357. /* The comparison may be able to be used. */
  358. break;
  359. }
  360. /* Point to next table */
  361. lpSqlNodeTables = ToNode(lpSql, lpSqlNodeTables->node.tables.Next);
  362. }
  363. }
  364. }
  365. /* If not <column> <op> <value> or <column> <op> <anothercolumn>, */
  366. /* the comparison can't be used */
  367. switch (lpSqlNodeValue->sqlNodeType) {
  368. case NODE_TYPE_CREATE:
  369. case NODE_TYPE_DROP:
  370. return ERR_INTERNAL;
  371. case NODE_TYPE_SELECT:
  372. return ERR_SUCCESS;
  373. case NODE_TYPE_INSERT:
  374. case NODE_TYPE_DELETE:
  375. case NODE_TYPE_UPDATE:
  376. case NODE_TYPE_CREATEINDEX:
  377. case NODE_TYPE_DROPINDEX:
  378. case NODE_TYPE_PASSTHROUGH:
  379. case NODE_TYPE_TABLES:
  380. case NODE_TYPE_VALUES:
  381. case NODE_TYPE_COLUMNS:
  382. case NODE_TYPE_SORTCOLUMNS:
  383. case NODE_TYPE_GROUPBYCOLUMNS:
  384. case NODE_TYPE_UPDATEVALUES:
  385. case NODE_TYPE_CREATECOLS:
  386. case NODE_TYPE_BOOLEAN:
  387. case NODE_TYPE_COMPARISON:
  388. return ERR_INTERNAL;
  389. case NODE_TYPE_ALGEBRAIC:
  390. case NODE_TYPE_SCALAR:
  391. case NODE_TYPE_AGGREGATE:
  392. return ERR_SUCCESS;
  393. case NODE_TYPE_TABLE:
  394. return ERR_INTERNAL;
  395. case NODE_TYPE_COLUMN:
  396. case NODE_TYPE_STRING:
  397. case NODE_TYPE_NUMERIC:
  398. case NODE_TYPE_PARAMETER:
  399. case NODE_TYPE_USER:
  400. case NODE_TYPE_NULL:
  401. case NODE_TYPE_DATE:
  402. case NODE_TYPE_TIME:
  403. case NODE_TYPE_TIMESTAMP:
  404. break;
  405. default:
  406. return ERR_INTERNAL;
  407. }
  408. /* If column is not in this table, the comparison cannot be used */
  409. lpTableAlias = ToString(lpSql, lpSqlNodeTable->node.table.Alias);
  410. lpColumnAlias = ToString(lpSql, lpSqlNodeColumn->node.column.Tablealias);
  411. if (lpSqlNodeTable != ToNode(lpSql, lpSqlNodeColumn->node.column.TableIndex))
  412. return NO_SQLNODE;
  413. /* This comparison can be used. Swap the sides if need be */
  414. if (fSwap) {
  415. idxLeft = lpSqlNodePredicate->node.comparison.Left;
  416. lpSqlNodePredicate->node.comparison.Left =
  417. lpSqlNodePredicate->node.comparison.Right;
  418. lpSqlNodePredicate->node.comparison.Right = idxLeft;
  419. switch (lpSqlNodePredicate->node.comparison.Operator) {
  420. case OP_EQ:
  421. case OP_NE:
  422. break;
  423. case OP_LE:
  424. lpSqlNodePredicate->node.comparison.Operator = OP_GE;
  425. break;
  426. case OP_LT:
  427. lpSqlNodePredicate->node.comparison.Operator = OP_GT;
  428. break;
  429. case OP_GE:
  430. lpSqlNodePredicate->node.comparison.Operator = OP_LE;
  431. break;
  432. case OP_GT:
  433. lpSqlNodePredicate->node.comparison.Operator = OP_LT;
  434. break;
  435. case OP_IN:
  436. case OP_NOTIN:
  437. case OP_LIKE:
  438. case OP_NOTLIKE:
  439. default:
  440. return ERR_INTERNAL;
  441. }
  442. }
  443. /* Get the selectivity of the column */
  444. ClassColumnInfoBase* cInfoBase = (lpSqlNodeTable->node.table.Handle)->pColumnInfo;
  445. if ( !cInfoBase->IsValid() )
  446. {
  447. return NO_SQLNODE;
  448. }
  449. lpSqlNodePredicate->node.comparison.fSelectivity = cInfoBase->GetSelectivity();
  450. /* Is the selectivity non-zero? */
  451. if (lpSqlNodePredicate->node.comparison.fSelectivity != 0) {
  452. /* Put the predicate on the list */
  453. idxPrev = NO_SQLNODE;
  454. idxCurr = *lpRestriction;
  455. while (idxCurr != NO_SQLNODE) {
  456. lpSqlNodePredicateCurr = ToNode(lpSql, idxCurr);
  457. if (lpSqlNodePredicateCurr->node.comparison.fSelectivity <
  458. lpSqlNodePredicate->node.comparison.fSelectivity)
  459. break;
  460. idxPrev = idxCurr;
  461. idxCurr = lpSqlNodePredicateCurr->node.comparison.NextRestrict;
  462. }
  463. lpSqlNodePredicate->node.comparison.NextRestrict = idxCurr;
  464. if (idxPrev != NO_SQLNODE) {
  465. lpSqlNodePredicatePrev = ToNode(lpSql, idxPrev);
  466. lpSqlNodePredicatePrev->node.comparison.NextRestrict = idxPredicate;
  467. }
  468. else {
  469. *lpRestriction = idxPredicate;
  470. }
  471. /* Increase count */
  472. *lpcRestriction = (*lpcRestriction) + 1;
  473. }
  474. return ERR_SUCCESS;
  475. }
  476. case NODE_TYPE_ALGEBRAIC:
  477. case NODE_TYPE_SCALAR:
  478. case NODE_TYPE_AGGREGATE:
  479. case NODE_TYPE_TABLE:
  480. case NODE_TYPE_COLUMN:
  481. case NODE_TYPE_STRING:
  482. case NODE_TYPE_NUMERIC:
  483. case NODE_TYPE_PARAMETER:
  484. case NODE_TYPE_USER:
  485. case NODE_TYPE_NULL:
  486. case NODE_TYPE_DATE:
  487. case NODE_TYPE_TIME:
  488. case NODE_TYPE_TIMESTAMP:
  489. default:
  490. return ERR_INTERNAL;
  491. }
  492. /* Control never gets here */
  493. }
  494. /***************************************************************************/
  495. RETCODE INTFUNC Optimize(LPSQLTREE lpSql, SQLNODEIDX idxStatement,
  496. BOOL fCaseSensitive)
  497. /* Optimizes a parse tree */
  498. {
  499. LPSQLNODE lpSqlNode;
  500. SQLNODEIDX idxPredicate;
  501. LPSQLNODE lpSqlNodeTableList;
  502. LPSQLNODE lpSqlNodeFirstTable;
  503. LPSQLNODE lpSqlNodeTables;
  504. LPSQLNODE lpSqlNodeTable;
  505. SQLNODEIDX idxSortcolumns;
  506. UWORD tableSequenceNumber;
  507. LPSQLNODE lpSqlNodeSortcolumns;
  508. LPSQLNODE lpSqlNodeColumn;
  509. LPUSTR lpColumnAlias;
  510. // LPUSTR lpTableAlias;
  511. UWORD idx;
  512. UWORD i;
  513. SQLNODEIDX idxTables;
  514. LPSQLNODE lpSqlNodeTablesPrev;
  515. RETCODE err;
  516. #define NUM_LEN 5
  517. /* Return if nothing to optimize */
  518. if (idxStatement == NO_SQLNODE)
  519. return ERR_SUCCESS;
  520. //Add table cartesian product optimization here
  521. LPSQLNODE lpRootNode = ToNode(lpSql, ROOT_SQLNODE);
  522. //Sai Wong
  523. LPSQLNODE lpSqlNode2 = ToNode(lpSql, lpRootNode->node.root.sql);
  524. // LPSQLNODE lpSqlNode2 = ToNode(lpSql, idxStatement);
  525. TableColumnInfo optimizationInfo (&lpRootNode, &lpSqlNode2);
  526. //For each table in table list, check if there are any references
  527. //to its child columns
  528. if (optimizationInfo.IsValid())
  529. {
  530. //Point to beginning of select list
  531. if (lpSqlNode2->node.select.Tables != NO_SQLNODE)
  532. {
  533. LPSQLNODE lpSelectList = ToNode(lpSql, lpSqlNode2->node.select.Tables);
  534. LPSQLNODE lpSqlNodeTable = NULL;
  535. LPSQLNODE lpPrevNode = NULL;
  536. SQLNODEIDX idxNode = NO_SQLNODE;
  537. SQLNODEIDX idxSelectNode = lpSqlNode2->node.select.Tables;
  538. SQLNODEIDX idxPrevNode = NO_SQLNODE;
  539. BOOL fFirstTime = TRUE;
  540. while (lpSelectList)
  541. {
  542. //Sai added
  543. SQLNODEIDX lpSqlNodeTables = lpSelectList->node.tables.Table;
  544. lpSqlNodeTable = ToNode(lpSql, lpSqlNodeTables);
  545. if ( optimizationInfo.IsTableReferenced(lpSqlNodeTable->node.table.Handle) ||
  546. optimizationInfo.IsZeroOrOneList() )
  547. {
  548. // ODBCTRACE ("\nWBEM ODBC Driver: Table is referenced or there is only one table\n");
  549. }
  550. else
  551. {
  552. ODBCTRACE ("\nWBEM ODBC Driver: Table is not referenced so we REMOVE FROM TABLELIST\n");
  553. //We now need to remove table from tablelist
  554. if (fFirstTime)
  555. {
  556. idxNode = lpSqlNode2->node.select.Tables;
  557. lpSqlNode2->node.select.Tables = lpSelectList->node.tables.Next;
  558. lpSelectList->node.tables.Next = NO_SQLNODE;
  559. // FreeTreeSemantic(lpSql, idxNode);
  560. //Prepare for next interation
  561. //fFirstTime = FALSE;
  562. idxSelectNode = lpSqlNode2->node.select.Tables;
  563. FreeTreeSemantic(lpSql, idxNode);
  564. if (idxSelectNode != NO_SQLNODE)
  565. {
  566. lpSelectList = ToNode(lpSql, idxSelectNode);
  567. }
  568. else
  569. {
  570. lpSelectList = NULL;
  571. }
  572. continue;
  573. }
  574. else
  575. {
  576. idxNode = lpPrevNode->node.tables.Next;
  577. lpPrevNode->node.tables.Next = lpSelectList->node.tables.Next;
  578. lpSelectList->node.tables.Next = NO_SQLNODE;
  579. // FreeTreeSemantic(lpSql, idxNode);
  580. //Prepare for next interation
  581. fFirstTime = FALSE;
  582. idxSelectNode = lpPrevNode->node.tables.Next;
  583. FreeTreeSemantic(lpSql, idxNode);
  584. if (idxSelectNode != NO_SQLNODE)
  585. {
  586. lpSelectList = ToNode(lpSql, idxSelectNode);
  587. lpPrevNode = ToNode(lpSql, idxPrevNode);
  588. }
  589. else
  590. {
  591. lpSelectList = NULL;
  592. }
  593. continue;
  594. }
  595. }
  596. //Prepare for next interation
  597. fFirstTime = FALSE;
  598. lpPrevNode = lpSelectList;
  599. idxPrevNode = idxSelectNode;
  600. if (lpSelectList->node.tables.Next != NO_SQLNODE)
  601. {
  602. idxSelectNode = lpSelectList->node.tables.Next;
  603. lpSelectList = ToNode(lpSql, idxSelectNode);
  604. }
  605. else
  606. {
  607. idxSelectNode = NO_SQLNODE;
  608. lpSelectList = NULL;
  609. }
  610. }
  611. }
  612. }
  613. /* Find predicate, list of tables, and first table on that list. At */
  614. /* the same time, walk the tree to optimize any nested sub-selects */
  615. lpSqlNode = ToNode(lpSql, idxStatement);
  616. lpSqlNodeTableList = NULL;
  617. lpSqlNodeFirstTable = NULL;
  618. switch (lpSqlNode->sqlNodeType) {
  619. case NODE_TYPE_CREATE:
  620. break;
  621. case NODE_TYPE_DROP:
  622. break;
  623. case NODE_TYPE_SELECT:
  624. /* Optimize any nested sub-selects */
  625. err = Optimize(lpSql, lpSqlNode->node.select.Tables, fCaseSensitive);
  626. if (err != ERR_SUCCESS)
  627. return err;
  628. err = Optimize(lpSql, lpSqlNode->node.select.Predicate, fCaseSensitive);
  629. if (err != ERR_SUCCESS)
  630. return err;
  631. err = Optimize(lpSql, lpSqlNode->node.select.Having, fCaseSensitive);
  632. if (err != ERR_SUCCESS)
  633. return err;
  634. lpSqlNodeTableList = ToNode(lpSql, lpSqlNode->node.select.Tables);
  635. lpSqlNodeFirstTable = ToNode(lpSql, lpSqlNodeTableList->node.tables.Table);
  636. idxPredicate = lpSqlNode->node.select.Predicate;
  637. break;
  638. case NODE_TYPE_INSERT:
  639. /* Optimize any nested sub-selects */
  640. err = Optimize(lpSql, lpSqlNode->node.insert.Values, fCaseSensitive);
  641. if (err != ERR_SUCCESS)
  642. return err;
  643. break;
  644. case NODE_TYPE_DELETE:
  645. /* Optimize any nested sub-selects */
  646. err = Optimize(lpSql, lpSqlNode->node.delet.Predicate, fCaseSensitive);
  647. if (err != ERR_SUCCESS)
  648. return err;
  649. lpSqlNodeTableList = NULL;
  650. lpSqlNodeFirstTable = ToNode(lpSql, lpSqlNode->node.delet.Table);
  651. idxPredicate = lpSqlNode->node.delet.Predicate;
  652. break;
  653. case NODE_TYPE_UPDATE:
  654. /* Optimize any nested sub-selects */
  655. err = Optimize(lpSql, lpSqlNode->node.update.Predicate, fCaseSensitive);
  656. if (err != ERR_SUCCESS)
  657. return err;
  658. lpSqlNodeTableList = NULL;
  659. lpSqlNodeFirstTable = ToNode(lpSql, lpSqlNode->node.update.Table);
  660. idxPredicate = lpSqlNode->node.update.Predicate;
  661. break;
  662. case NODE_TYPE_CREATEINDEX:
  663. break;
  664. case NODE_TYPE_DROPINDEX:
  665. break;
  666. case NODE_TYPE_PASSTHROUGH:
  667. break;
  668. case NODE_TYPE_TABLES:
  669. /* Optimize any nested sub-selects */
  670. err = Optimize(lpSql, lpSqlNode->node.tables.Table, fCaseSensitive);
  671. if (err != ERR_SUCCESS)
  672. return err;
  673. err = Optimize(lpSql, lpSqlNode->node.tables.Next, fCaseSensitive);
  674. if (err != ERR_SUCCESS)
  675. return err;
  676. break;
  677. case NODE_TYPE_VALUES:
  678. break;
  679. case NODE_TYPE_COLUMNS:
  680. case NODE_TYPE_SORTCOLUMNS:
  681. case NODE_TYPE_GROUPBYCOLUMNS:
  682. case NODE_TYPE_UPDATEVALUES:
  683. case NODE_TYPE_CREATECOLS:
  684. return ERR_INTERNAL;
  685. case NODE_TYPE_BOOLEAN:
  686. /* Optimize any nested sub-selects */
  687. while (TRUE) {
  688. /* Optimize left child */
  689. err = Optimize(lpSql, lpSqlNode->node.boolean.Left, fCaseSensitive);
  690. if (err != ERR_SUCCESS)
  691. return err;
  692. /* Leave loop if no right child */
  693. if (lpSqlNode->node.boolean.Right == NO_SQLNODE)
  694. break;
  695. /* Is right child a NODE_TYPE_BOOLEAN node? */
  696. if (ToNode(lpSql, lpSqlNode->node.boolean.Right)->sqlNodeType !=
  697. NODE_TYPE_BOOLEAN) {
  698. /* No. Optimize that and leave the loop */
  699. err = Optimize(lpSql, lpSqlNode->node.boolean.Right,
  700. fCaseSensitive);
  701. if (err != ERR_SUCCESS)
  702. return err;
  703. break;
  704. }
  705. /* Optimize the right node on next iteration of the loop */
  706. lpSqlNode = ToNode(lpSql, lpSqlNode->node.boolean.Right);
  707. }
  708. break;
  709. case NODE_TYPE_COMPARISON:
  710. /* Optimize any nested sub-selects */
  711. if (lpSqlNode->node.comparison.Operator == OP_EXISTS) {
  712. err = Optimize(lpSql, lpSqlNode->node.comparison.Left,
  713. fCaseSensitive);
  714. if (err != ERR_SUCCESS)
  715. return err;
  716. }
  717. else if (lpSqlNode->node.comparison.SelectModifier !=
  718. SELECT_NOTSELECT) {
  719. err = Optimize(lpSql, lpSqlNode->node.comparison.Right,
  720. fCaseSensitive);
  721. if (err != ERR_SUCCESS)
  722. return err;
  723. }
  724. break;
  725. case NODE_TYPE_ALGEBRAIC:
  726. case NODE_TYPE_SCALAR:
  727. case NODE_TYPE_AGGREGATE:
  728. return ERR_INTERNAL;
  729. case NODE_TYPE_TABLE:
  730. /* Optimize any nested sub-selects */
  731. err = Optimize(lpSql, lpSqlNode->node.table.OuterJoinPredicate,
  732. fCaseSensitive);
  733. if (err != ERR_SUCCESS)
  734. return err;
  735. break;
  736. case NODE_TYPE_COLUMN:
  737. case NODE_TYPE_STRING:
  738. case NODE_TYPE_NUMERIC:
  739. case NODE_TYPE_PARAMETER:
  740. case NODE_TYPE_USER:
  741. case NODE_TYPE_NULL:
  742. case NODE_TYPE_DATE:
  743. case NODE_TYPE_TIME:
  744. case NODE_TYPE_TIMESTAMP:
  745. default:
  746. return ERR_INTERNAL;
  747. }
  748. /* Is this a SELECT statement? */
  749. if (lpSqlNode->sqlNodeType == NODE_TYPE_SELECT) {
  750. /* Yes. For each sort column... */
  751. idxSortcolumns = lpSqlNode->node.select.Sortcolumns;
  752. tableSequenceNumber = 0;
  753. while ((idxSortcolumns != NO_SQLNODE) &&
  754. (lpSqlNode->node.select.Groupbycolumns == NO_SQLNODE) &&
  755. (!lpSqlNode->node.select.ImplicitGroupby) &&
  756. (!lpSqlNode->node.select.Distinct)) {
  757. /* Get the sort column */
  758. lpSqlNodeSortcolumns = ToNode(lpSql, idxSortcolumns);
  759. lpSqlNodeColumn = ToNode(lpSql,
  760. lpSqlNodeSortcolumns->node.sortcolumns.Column);
  761. /* If not a simple column reference, we cannot optimize the */
  762. /* sort by simply rearranging the order the tables are cycled */
  763. /* through and pushing the sorting down to the ISAM level. */
  764. /* Leave the loop */
  765. if (lpSqlNodeColumn->sqlNodeType != NODE_TYPE_COLUMN)
  766. break;
  767. /* Get the sort column's table name */
  768. lpColumnAlias = ToString(lpSql, lpSqlNodeColumn->node.column.Tablealias);
  769. /* Find the table of the column on the table list */
  770. lpSqlNodeTable = ToNode(lpSql, lpSqlNodeColumn->node.column.TableIndex);
  771. /* We cannot pushdown the sort if it involves an outer join */
  772. /* column. Leave the loop */
  773. if (lpSqlNodeTable->node.table.OuterJoinPredicate != NO_SQLNODE)
  774. break;
  775. /* Has a column for this table already been found in sort list? */
  776. if (lpSqlNodeTable->node.table.Sortsequence == 0) {
  777. /* No. This is the beginning of a sequence of columns for */
  778. /* this table. Save the sequence number. */
  779. tableSequenceNumber++;
  780. lpSqlNodeTable->node.table.Sortsequence = tableSequenceNumber;
  781. lpSqlNodeTable->node.table.Sortcount = 1;
  782. lpSqlNodeTable->node.table.Sortcolumns = idxSortcolumns;
  783. }
  784. else {
  785. /* Yes. If not part of the current table sequence we */
  786. /* cannot optimize the sort by simply rearranging the */
  787. /* order the tables are cycled through and pushing the */
  788. /* sorting down to the ISAM level. Leave the loop */
  789. if (lpSqlNodeTable->node.table.Sortsequence != tableSequenceNumber)
  790. break;
  791. /* Increase the number of columns to sort this table by */
  792. lpSqlNodeTable->node.table.Sortcount++;
  793. }
  794. /* Do the next column */
  795. idxSortcolumns = lpSqlNodeSortcolumns->node.sortcolumns.Next;
  796. }
  797. /* Can we optimize the sort by pushing the sorting down to the */
  798. /* ISAM level? */
  799. if ((idxSortcolumns == NO_SQLNODE) &&
  800. (lpSqlNode->node.select.Groupbycolumns == NO_SQLNODE) &&
  801. (!lpSqlNode->node.select.ImplicitGroupby) &&
  802. (!lpSqlNode->node.select.Distinct)) {
  803. /* Yes. Rearrange the table order. Move the table with the */
  804. /* first sort column to the front of the table table list, */
  805. /* move the table of the second column to the next position, */
  806. /* etc. The processing of a SELECT statement does a cartesian */
  807. /* product of the tables on the table list, with the table at */
  808. /* the beginning of the list "spinning" slowest (see */
  809. /* NextRecord() in EVALUATE.C). Putting the table with the */
  810. /* first column to sort by at the front of the list will cause */
  811. /* the records to be considered in sorted order at execution */
  812. /* time. For each table with sort columns... */
  813. for (idx = 0; idx < tableSequenceNumber; idx++) {
  814. /* Find the idx'th table */
  815. idxTables = lpSqlNode->node.select.Tables;
  816. lpSqlNodeTables = lpSqlNodeTableList;
  817. lpSqlNodeTable = lpSqlNodeFirstTable;
  818. lpSqlNodeTablesPrev = NULL;
  819. while (TRUE) {
  820. /* If this is the table, leave the loop */
  821. if (lpSqlNodeTable->node.table.Sortsequence == (idx + 1))
  822. break;
  823. /* Internal error if no more tables */
  824. if (lpSqlNodeTables == NULL)
  825. return ERR_INTERNAL;
  826. if (lpSqlNodeTables->node.tables.Next == NO_SQLNODE)
  827. return ERR_INTERNAL;
  828. /* Do the next table on the list */
  829. lpSqlNodeTablesPrev = lpSqlNodeTables;
  830. idxTables = lpSqlNodeTables->node.tables.Next;
  831. lpSqlNodeTables = ToNode(lpSql, lpSqlNodeTables->node.tables.Next);
  832. lpSqlNodeTable = ToNode(lpSql, lpSqlNodeTables->node.tables.Table);
  833. }
  834. /* Remove the table found from the list */
  835. if (lpSqlNodeTablesPrev == NULL)
  836. lpSqlNode->node.select.Tables = lpSqlNodeTables->node.tables.Next;
  837. else
  838. lpSqlNodeTablesPrev->node.tables.Next =
  839. lpSqlNodeTables->node.tables.Next;
  840. /* Find the entry before the idx'th position of the list */
  841. lpSqlNodeTablesPrev = NULL;
  842. for (i=0; i < idx; i++) {
  843. if (lpSqlNodeTablesPrev == NULL)
  844. lpSqlNodeTablesPrev =
  845. ToNode(lpSql, lpSqlNode->node.select.Tables);
  846. else
  847. lpSqlNodeTablesPrev =
  848. ToNode(lpSql, lpSqlNodeTablesPrev->node.tables.Next);
  849. }
  850. /* Put the table found in the idx'th position of the list */
  851. if (lpSqlNodeTablesPrev == NULL) {
  852. lpSqlNodeTables->node.tables.Next = lpSqlNode->node.select.Tables;
  853. lpSqlNode->node.select.Tables = idxTables;
  854. }
  855. else {
  856. lpSqlNodeTables->node.tables.Next =
  857. lpSqlNodeTablesPrev->node.tables.Next;
  858. lpSqlNodeTablesPrev->node.tables.Next = idxTables;
  859. }
  860. /* Recalculate the table list and table pointers */
  861. lpSqlNodeTableList = ToNode(lpSql, lpSqlNode->node.select.Tables);
  862. lpSqlNodeFirstTable = ToNode(lpSql,
  863. lpSqlNodeTableList->node.tables.Table);
  864. }
  865. /* Set flag to enable the pushdown sort */
  866. lpSqlNode->node.select.fPushdownSort = TRUE;
  867. }
  868. else {
  869. /* No. Remove the markers */
  870. lpSqlNodeTables = lpSqlNodeTableList;
  871. lpSqlNodeTable = lpSqlNodeFirstTable;
  872. while (TRUE) {
  873. /* Remove the markers for this table */
  874. lpSqlNodeTable->node.table.Sortsequence = 0;
  875. lpSqlNodeTable->node.table.Sortcount = 0;
  876. lpSqlNodeTable->node.table.Sortcolumns = NO_SQLNODE;
  877. /* Leave if no more tables */
  878. if (lpSqlNodeTables == NULL)
  879. break;
  880. if (lpSqlNodeTables->node.tables.Next == NO_SQLNODE)
  881. break;
  882. /* Do the next table on the list */
  883. lpSqlNodeTables = ToNode(lpSql, lpSqlNodeTables->node.tables.Next);
  884. lpSqlNodeTable = ToNode(lpSql, lpSqlNodeTables->node.tables.Table);
  885. }
  886. }
  887. }
  888. /* For each table... */
  889. lpSqlNodeTables = lpSqlNodeTableList;
  890. lpSqlNodeTable = lpSqlNodeFirstTable;
  891. while (lpSqlNodeTable != NULL) {
  892. /* Find the selective conditions that uses a column in this table */
  893. lpSqlNodeTable->node.table.cRestrict = 0;
  894. lpSqlNodeTable->node.table.Restrict = NO_SQLNODE;
  895. if (lpSqlNodeTable->node.table.OuterJoinPredicate == NO_SQLNODE)
  896. FindRestriction(lpSql, fCaseSensitive, lpSqlNodeTable,
  897. idxPredicate, idxStatement,
  898. &(lpSqlNodeTable->node.table.cRestrict),
  899. &(lpSqlNodeTable->node.table.Restrict));
  900. else
  901. FindRestriction(lpSql, fCaseSensitive, lpSqlNodeTable,
  902. lpSqlNodeTable->node.table.OuterJoinPredicate,
  903. idxStatement, &(lpSqlNodeTable->node.table.cRestrict),
  904. &(lpSqlNodeTable->node.table.Restrict));
  905. /* Leave if no more tables */
  906. if (lpSqlNodeTables == NULL)
  907. break;
  908. if (lpSqlNodeTables->node.tables.Next == NO_SQLNODE)
  909. break;
  910. /* Do the next table on the list */
  911. lpSqlNodeTables = ToNode(lpSql, lpSqlNodeTables->node.tables.Next);
  912. lpSqlNodeTable = ToNode(lpSql, lpSqlNodeTables->node.tables.Table);
  913. }
  914. /* Check to see if this is a funny MSAccess query */
  915. if ((lpSqlNode->sqlNodeType == NODE_TYPE_SELECT) &&
  916. (!(lpSqlNode->node.select.Distinct)) &&
  917. (lpSqlNodeTableList->node.tables.Next == NO_SQLNODE) &&
  918. (lpSqlNode->node.select.Groupbycolumns == NO_SQLNODE) &&
  919. (lpSqlNode->node.select.Having == NO_SQLNODE) &&
  920. (lpSqlNode->node.select.Sortcolumns == NO_SQLNODE) &&
  921. (ToNode(lpSql, ROOT_SQLNODE)->node.root.sql == idxStatement)) {
  922. if (CheckMSAccessPredicate(lpSql, lpSqlNode->node.select.Predicate)) {
  923. lpSqlNode->node.select.fMSAccess = TRUE;
  924. lpSqlNode->node.select.SortRecordsize = NUM_LEN + sizeof(ISAMBOOKMARK);
  925. lpSqlNode->node.select.SortBookmarks = NUM_LEN + 1;
  926. }
  927. }
  928. return ERR_SUCCESS;
  929. }
  930. /***************************************************************************/