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.

554 lines
15 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: CONVERT.CXX
  7. //
  8. // Contents: Restriction to cursor converter
  9. //
  10. // Classes: CConverter
  11. //
  12. // History: 16-Jul-92 MikeHew Created
  13. // 01-Feb-93 KyleP Convert restrictions
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <curstk.hxx>
  19. #include <convert.hxx>
  20. #include <ocursor.hxx>
  21. #include <querble.hxx>
  22. #include <cudebug.hxx>
  23. #include "phrcur.hxx"
  24. #include "andcur.hxx"
  25. #include "orcursor.hxx"
  26. #include "veccurs.hxx"
  27. #include "proxcur.hxx"
  28. #include "andncur.hxx"
  29. //+---------------------------------------------------------------------------
  30. //
  31. // Member: CConverter::CConverter, public
  32. //
  33. // Synopsis:
  34. //
  35. // Arguments: [pQuerble] -- Index
  36. // [cMaxNodes] -- Maximum number of nodes to build
  37. //
  38. // History: 15-Jul-92 MikeHew Created
  39. //
  40. //----------------------------------------------------------------------------
  41. CConverter::CConverter( CQueriable * pQuerble, ULONG cMaxNodes )
  42. : _pQuerble( pQuerble ),
  43. _cNodesRemaining( cMaxNodes )
  44. {
  45. } //CConverter
  46. //+---------------------------------------------------------------------------
  47. //
  48. // Member: CConverter::QueryCursor, public
  49. //
  50. // Synopsis: Walk the query tree, create cursor tree
  51. //
  52. // Arguments: [pRst] -- Tree of query restrictions
  53. //
  54. // History: 15-Jul-92 MikeHew Created
  55. //
  56. //----------------------------------------------------------------------------
  57. CCursor* CConverter::QueryCursor( CRestriction const * pRst )
  58. {
  59. //
  60. // go through leaves, get cursors from index
  61. // combine them into a cursor tree
  62. //
  63. if ( 0 != pRst )
  64. return ConvertRst( pRst );
  65. return 0;
  66. } //QueryCursor
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Member: CConverter::ConvertRst, private
  70. //
  71. // Synopsis: Walk the query tree, create cursor tree
  72. //
  73. // Arguments: [pRst] -- Tree of query restrictions
  74. //
  75. // History: 15-Jul-92 MikeHew Created
  76. //
  77. //----------------------------------------------------------------------------
  78. CCursor* CConverter::ConvertRst( CRestriction const * pRst )
  79. {
  80. TRY
  81. {
  82. if ( pRst->IsLeaf() )
  83. return ConvertLeaf ( pRst );
  84. switch ( pRst->Type() )
  85. {
  86. case RTPhrase:
  87. return ConvertPhraseNode ( pRst->CastToNode() );
  88. case RTProximity:
  89. return ConvertProxNode ( pRst->CastToNode() );
  90. case RTVector:
  91. return ConvertVectorNode ( pRst->CastToNode() );
  92. case RTAnd:
  93. case RTOr:
  94. return ConvertNode ( pRst->CastToNode() );
  95. default:
  96. cuDebugOut(( DEB_ERROR,
  97. "Restriction type %d cannot be converted to cursor\n", pRst->Type() ));
  98. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  99. }
  100. }
  101. CATCH( CException, e )
  102. {
  103. if ( !TooManyNodes() )
  104. RETHROW();
  105. }
  106. END_CATCH
  107. return 0;
  108. } //ConvertRst
  109. //+---------------------------------------------------------------------------
  110. //
  111. // Member: CConverter::ConvertPhraseNode, private
  112. //
  113. // Synopsis: Convert a phrase node to a COccCursor.
  114. //
  115. // Arguments: [pNodeRst] -- Restriction
  116. //
  117. // Returns: COccCursor
  118. //
  119. // History: 19-Sep-91 BartoszM Created.
  120. // 15-Apr-92 AmyA Changed from ConvertOccNode and return
  121. // value from CCursor. Moved code for
  122. // proximity node to ConvertProxNode.
  123. // 16-Jul-92 MikeHew Yanked out of CQParse and put into
  124. // CConverter
  125. //
  126. //----------------------------------------------------------------------------
  127. COccCursor* CConverter::ConvertPhraseNode( CNodeRestriction const * pNodeRst )
  128. {
  129. Win4Assert( RTPhrase == pNodeRst->Type() );
  130. unsigned cChild = pNodeRst->Count();
  131. if ( cChild == 0 )
  132. return 0;
  133. if ( cChild == 1 )
  134. return ConvertLeaf ( pNodeRst->GetChild(0) );
  135. COccCurStack curStack ( cChild );
  136. // Get all the cursors
  137. for ( unsigned i = 0; i < cChild; i++ )
  138. {
  139. CRestriction* pChild = pNodeRst->GetChild(i);
  140. COccCursor* pCur = ConvertLeaf ( pChild );
  141. if ( pCur == 0 )
  142. break;
  143. curStack.Push( pCur );
  144. }
  145. // Combine all the cursors
  146. unsigned cCur = curStack.Count();
  147. if ( cCur < cChild )
  148. return 0;
  149. XArray<OCCURRENCE> aOcc (cCur);
  150. CWordRestriction* wordRst = (CWordRestriction*) pNodeRst->GetChild(0);
  151. OCCURRENCE occStart = wordRst->Occurrence();
  152. for ( unsigned k = 0; k < cCur; k++ )
  153. {
  154. wordRst = (CWordRestriction*) pNodeRst->GetChild(k);
  155. aOcc[k] = wordRst->Occurrence() - occStart;
  156. }
  157. return new CPhraseCursor( curStack, aOcc );
  158. } //ConvertPhraseNode
  159. //+---------------------------------------------------------------------------
  160. //
  161. // Member: CConverter::ConvertProxNode, private
  162. //
  163. // Synopsis: Convert a Proximity node into a CCursor.
  164. //
  165. // Arguments: [pNodeRst] -- Restriction
  166. //
  167. // Returns: CCursor
  168. //
  169. // History: 15-Apr-92 AmyA Created.
  170. // 16-Jul-92 MikeHew Yanked out of CQParse and put into
  171. // CConverter
  172. //
  173. //----------------------------------------------------------------------------
  174. CCursor* CConverter::ConvertProxNode( CNodeRestriction const * pNodeRst )
  175. {
  176. Win4Assert ( pNodeRst->Type() == RTProximity );
  177. unsigned cChild = pNodeRst->Count();
  178. if ( cChild == 0 )
  179. return 0;
  180. // We don't support queries like: foo ~ !bar
  181. if ( cChild == 1 )
  182. {
  183. CRestriction * pRst = pNodeRst->GetChild(0);
  184. if ( pRst->IsLeaf() )
  185. return ConvertLeaf( pRst );
  186. else if ( RTPhrase == pRst->Type() )
  187. return ConvertPhraseNode ( pRst->CastToNode() );
  188. else
  189. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  190. }
  191. COccCurStack curStack ( cChild );
  192. // Get all the cursors
  193. for ( unsigned i = 0; i < cChild; i++ )
  194. {
  195. CRestriction * pChild = pNodeRst->GetChild(i);
  196. COccCursor * pCur;
  197. if ( pChild->IsLeaf() )
  198. pCur = ConvertLeaf( pChild );
  199. else if ( RTPhrase == pChild->Type() )
  200. pCur = ConvertPhraseNode ( pChild->CastToNode() );
  201. else
  202. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  203. if ( pCur != 0 )
  204. curStack.Push(pCur);
  205. }
  206. // Combine all the cursors
  207. unsigned cCur = curStack.Count();
  208. if ( cCur < cChild )
  209. {
  210. cuDebugOut (( DEB_ITRACE, "prox:Fewer cursors than expected\n" ));
  211. return 0;
  212. }
  213. return new CProxCursor ( cCur, curStack );
  214. } //ConvertProxNode
  215. //+---------------------------------------------------------------------------
  216. //
  217. // Member: CConverter::ConvertAndNotNode, private
  218. //
  219. // Synopsis: Convert an And Not node into a CCursor.
  220. //
  221. // Arguments: [pNodeRst] -- Restriction
  222. //
  223. // Returns: CCursor
  224. //
  225. // Notes: Will return 0 if there is not exactly two children nodes.
  226. //
  227. // History: 22-Apr-92 AmyA Created.
  228. // 16-Jul-92 MikeHew Yanked out of CQParse and put into
  229. // CConverter
  230. //
  231. //----------------------------------------------------------------------------
  232. CCursor* CConverter::ConvertAndNotNode( XCursor & curSrc, CCurStack & curNot )
  233. {
  234. Win4Assert( curNot.Count() > 0 );
  235. XCursor Cur;
  236. //
  237. // Note we should convert (a & b & !c) to (a & ( b & !c ) ),
  238. // Also, convert !a & b to b & !a
  239. // This code has been substantially rewritten in Babylon.
  240. //
  241. while ( curNot.Count() > 0 )
  242. {
  243. XCursor curFilter( curNot.Pop() );
  244. //
  245. // WARNING: Don't put any code between the next two lines if that
  246. // code can THROW.
  247. //
  248. CCursor * pTemp = new CAndNotCursor( curSrc, curFilter );
  249. curSrc.Set( pTemp );
  250. }
  251. return curSrc.Acquire();
  252. } //ConvertAndNotNode
  253. //+---------------------------------------------------------------------------
  254. //
  255. // Member: CConverter::ConvertVectorNode, private
  256. //
  257. // Synopsis: Convert an Or, And, or AndNot node into a CCursor.
  258. //
  259. // Arguments: [pNodeRst] -- Restriction
  260. //
  261. // Returns: CCursor
  262. //
  263. // History: 21-Oct-92 KyleP Created.
  264. //
  265. // Notes: This function is very similar to ConvertNode. The main
  266. // difference is that noise Restrictions have been preserved
  267. // in the vector input and maintain their position as place
  268. // holders in the vector.
  269. //
  270. //----------------------------------------------------------------------------
  271. CCursor* CConverter::ConvertVectorNode( CNodeRestriction const * pNodeRst )
  272. {
  273. unsigned cChild = pNodeRst->Count();
  274. if ( cChild == 0 )
  275. return 0;
  276. CCurStack curStack ( cChild );
  277. // Get all the cursors
  278. for ( unsigned i = 0; i < cChild; i++ )
  279. {
  280. CRestriction* pChild = pNodeRst->GetChild(i);
  281. CCursor* pCur = pChild ? ConvertRst ( pChild ) : 0;
  282. if ( pCur != 0 )
  283. {
  284. ULONG wt = pChild->Weight();
  285. pCur->SetWeight( min( wt, MAX_QUERY_RANK ) );
  286. }
  287. curStack.Push(pCur);
  288. }
  289. // Combine all the cursors
  290. Win4Assert( curStack.Count() == cChild );
  291. return new CVectorCursor( cChild,
  292. curStack,
  293. ((CVectorRestriction *)
  294. pNodeRst)->RankMethod() );
  295. } //ConvertVectorNode
  296. //+---------------------------------------------------------------------------
  297. //
  298. // Member: CConverter::ConvertNode, private
  299. //
  300. // Synopsis: Convert an Or, And, or AndNot node into a CCursor.
  301. //
  302. // Arguments: [pNodeRst] -- Restriction
  303. //
  304. // Returns: CCursor
  305. //
  306. // History: 19-Sep-91 BartoszM Created.
  307. // 23-Jun-92 MikeHew Added weight transfering.
  308. // 16-Jul-92 MikeHew Yanked out of CQParse and put into
  309. // CConverter
  310. //
  311. //----------------------------------------------------------------------------
  312. CCursor* CConverter::ConvertNode( CNodeRestriction const * pNodeRst )
  313. {
  314. unsigned cChild = pNodeRst->Count();
  315. if ( cChild == 0 )
  316. return 0;
  317. if ( cChild == 1 )
  318. return ConvertRst ( pNodeRst->GetChild(0) );
  319. BOOL fNullCursor = FALSE;
  320. BOOL fNullNotCursor = FALSE;
  321. CCurStack curStack ( cChild );
  322. CCurStack curNot( 1 );
  323. // Get all the cursors
  324. for ( unsigned i = 0; i < cChild; i++ )
  325. {
  326. CRestriction* pChild = pNodeRst->GetChild(i);
  327. CCursor * pCur = 0;
  328. if ( pChild->Type() == RTNot )
  329. {
  330. pChild = ((CNotRestriction *)pChild)->GetChild();
  331. pCur = ConvertRst( pChild );
  332. if ( 0 == pCur )
  333. fNullNotCursor = TRUE;
  334. else
  335. curNot.Push(pCur);
  336. }
  337. else
  338. {
  339. pCur = ConvertRst( pChild );
  340. if ( 0 == pCur )
  341. fNullCursor = TRUE;
  342. else
  343. curStack.Push(pCur);
  344. }
  345. if ( 0 != pCur )
  346. {
  347. ULONG wt = pChild->Weight();
  348. pCur->SetWeight( min( wt, MAX_QUERY_RANK ) );
  349. }
  350. }
  351. //
  352. // Combine all the cursors
  353. //
  354. unsigned cCur = curStack.Count();
  355. switch ( pNodeRst->Type() )
  356. {
  357. case RTAnd:
  358. {
  359. if ( curStack.Count() == 0
  360. && !fNullCursor
  361. && (curNot.Count() > 0 || fNullNotCursor) )
  362. {
  363. //
  364. // !cat & !dog is an invalid content restriction
  365. //
  366. cuDebugOut(( DEB_ERROR,
  367. "Content AND combined with only NOT nodes\n" ));
  368. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  369. }
  370. if ( fNullCursor || curStack.Count() == 0 )
  371. return 0;
  372. XCursor cur;
  373. if ( curStack.Count() == 1 )
  374. cur.Set( curStack.Pop() );
  375. else
  376. cur.Set( new CAndCursor ( cCur, curStack ) );
  377. if ( curNot.Count() > 0 )
  378. return( ConvertAndNotNode( cur, curNot ) );
  379. else
  380. return( cur.Acquire() );
  381. }
  382. case RTOr:
  383. {
  384. if ( curNot.Count() > 0 )
  385. {
  386. cuDebugOut(( DEB_ERROR,
  387. "Content NOT combined with OR node. Must be AND.\n",
  388. pNodeRst->Type() ));
  389. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  390. }
  391. if ( 0 == cCur )
  392. return 0;
  393. if ( cCur == 1 )
  394. return curStack.Pop();
  395. return new COrCursor ( cCur, curStack );
  396. }
  397. default:
  398. cuDebugOut(( DEB_ERROR,
  399. "Restriction type %d not implemented\n",
  400. pNodeRst->Type() ));
  401. THROW( CException( QUERY_E_INVALIDRESTRICTION ) );
  402. }
  403. return 0;
  404. } //ConvertNode
  405. //+---------------------------------------------------------------------------
  406. //
  407. // Member: CConverter::ConvertLeaf, private
  408. //
  409. // Synopsis: Convert a leaf node to a cursor
  410. //
  411. // Arguments: [pNodeRst] -- Restriction
  412. //
  413. // Returns: cursor
  414. //
  415. // History: 19-Sep-91 BartoszM Created.
  416. // 16-Jul-92 MikeHew Yanked out of CQParse and put into
  417. // CConverter
  418. //
  419. //----------------------------------------------------------------------------
  420. COccCursor* CConverter::ConvertLeaf( CRestriction const * pRst )
  421. {
  422. if ( TooManyNodes() )
  423. {
  424. ciDebugOut(( DEB_WARN, "Node limit reached (detected) in CConverter::ConverLeaf.\n" ));
  425. THROW( CException( STATUS_TOO_MANY_NODES ) );
  426. }
  427. switch ( pRst->Type() )
  428. {
  429. case RTWord:
  430. {
  431. CWordRestriction* wordRst = (CWordRestriction*) pRst;
  432. const CKey* pKey = wordRst->GetKey();
  433. return _pQuerble->QueryCursor( pKey, wordRst->IsRange(), _cNodesRemaining );
  434. }
  435. case RTSynonym:
  436. {
  437. CSynRestriction* pSynRst = (CSynRestriction*) pRst;
  438. CKeyArray& keyArray = pSynRst->GetKeys();
  439. return _pQuerble->QuerySynCursor ( keyArray, pSynRst->IsRange(), _cNodesRemaining );
  440. }
  441. case RTRange:
  442. {
  443. CRangeRestriction* pRangRst = (CRangeRestriction*) pRst;
  444. COccCursor * pCursor = _pQuerble->QueryRangeCursor ( pRangRst->GetStartKey(),
  445. pRangRst->GetEndKey(),
  446. _cNodesRemaining );
  447. if( 0 != pCursor && pidUnfiltered == pRangRst->Pid() )
  448. pCursor->SetUnfilteredOnly( TRUE );
  449. return pCursor;
  450. }
  451. default:
  452. cuDebugOut(( DEB_ITRACE, "Wrong type for occurrence leaf\n" ));
  453. return 0;
  454. }
  455. } //ConvertLeaf